public async Task <string> Kill(Grunt grunt, GruntCommand command, List <ParsedParameter> parameters) { if (parameters.Count() != 1) { StringBuilder toPrint = new StringBuilder(); toPrint.Append(EliteConsole.PrintFormattedErrorLine("Usage: Kill")); return(toPrint.ToString()); } GruntTask killTask = await _context.GetGruntTaskByName("Kill"); await _context.CreateGruntTasking(new GruntTasking { Id = 0, GruntId = grunt.Id, GruntTaskId = killTask.Id, GruntTask = killTask, Name = Guid.NewGuid().ToString().Replace("-", "").Substring(0, 10), Status = GruntTaskingStatus.Uninitialized, Type = GruntTaskingType.Kill, GruntCommand = command, GruntCommandId = command.Id }, _grunthub); return(""); }
public async Task <string> Connect(Grunt grunt, GruntCommand command, List <ParsedParameter> parameters) { string Name = "Connect"; StringBuilder toPrint = new StringBuilder(); if (parameters.Count < 2 || parameters.Count > 3 || !parameters[0].Value.Equals(Name, StringComparison.OrdinalIgnoreCase)) { return(EliteConsole.PrintFormattedErrorLine("Usage: Connect <ComputerName> [ <PipeName> ]")); } GruntTask connectTask = await _context.GetGruntTaskByName("Connect"); string PipeName = "gruntsvc"; if (parameters.Count == 3) { PipeName = parameters[2].Value; } await _context.CreateGruntTasking(new GruntTasking { Id = 0, GruntId = grunt.Id, GruntTaskId = connectTask.Id, GruntTask = connectTask, Name = Guid.NewGuid().ToString().Replace("-", "").Substring(0, 10), Status = GruntTaskingStatus.Uninitialized, Type = GruntTaskingType.Connect, Parameters = new List <string> { parameters[1].Value, PipeName }, GruntCommand = command, GruntCommandId = command.Id }, _grunthub); return(toPrint.ToString()); }
public async Task <string> History(Grunt grunt, List <ParsedParameter> parameters) { string Name = "History"; if (parameters.Count() != 2 || !parameters[0].Value.Equals(Name, StringComparison.OrdinalIgnoreCase)) { StringBuilder toPrint1 = new StringBuilder(); toPrint1.Append(EliteConsole.PrintFormattedErrorLine("Usage: History <tasking_name>")); return(toPrint1.ToString()); } StringBuilder toPrint = new StringBuilder(); GruntTasking tasking = await _context.GruntTaskings.FirstOrDefaultAsync(GT => GT.Name == parameters[1].Value); if (tasking == null) { toPrint.Append(EliteConsole.PrintFormattedErrorLine("Invalid History command, invalid tasking name. Usage is: History [ <tasking_name> ]")); } else { GruntCommand command = await _context.GruntCommands .Include(GC => GC.CommandOutput) .Include(GC => GC.User) .FirstOrDefaultAsync(GC => GC.Id == tasking.GruntCommandId); toPrint.Append(EliteConsole.PrintFormattedInfoLine("[" + tasking.CompletionTime + " UTC] Grunt: " + grunt.Name + " " + "GruntTasking: " + tasking.Name)); toPrint.Append(EliteConsole.PrintInfoLine("(" + command.User.UserName + ") > " + command.Command)); toPrint.Append(EliteConsole.PrintInfoLine(command.CommandOutput.Output)); } return(toPrint.ToString()); }
public async Task <string> Jobs(Grunt grunt, GruntCommand command, List <ParsedParameter> parameters) { string Name = "Jobs"; if (parameters.Count != 1 || !parameters[0].Value.Equals(Name, StringComparison.OrdinalIgnoreCase)) { return(EliteConsole.PrintFormattedErrorLine("Usage: Jobs")); } GruntTask jobsTask = await _context.GetGruntTaskByName("Jobs"); await _context.CreateGruntTasking(new GruntTasking { Id = 0, GruntId = grunt.Id, GruntTaskId = jobsTask.Id, GruntTask = jobsTask, Name = Guid.NewGuid().ToString().Replace("-", "").Substring(0, 10), Status = GruntTaskingStatus.Uninitialized, Type = GruntTaskingType.Jobs, Parameters = new List <string> { "Jobs" }, GruntCommand = command, GruntCommandId = command.Id }, _grunthub); return(""); }
public static async void DoReceiveCommandEvent(string command, string taskingEvent) { try { JObject o = JObject.Parse(taskingEvent); JObject o2 = JObject.Parse(command); // Because this call is not awaited, execution of the current method continues before the call is completed Task.Run(() => { GruntCommand comm = JsonConvert.DeserializeObject <GruntCommand>(command); if (o["messageHeader"].ToString().Contains("completed") && !o["messageBody"].ToString().Contains("Grunts.CommandOutput")) { try { Program.tasks[Program.tasks.FindIndex(c => c.Id == comm.Id)] = comm; } catch { Console.WriteLine("[Forerunner] Returned tasks didn't originate from us. Handling via GlobalFunc"); string scriptCode = File.ReadAllText("Forerunner.lua"); Script script = Common.GetScript(comm.Grunt, comm); script.DoString(scriptCode); Task.Run(() => { script.Call(script.Globals["OnGlobalOutput"], comm.CommandOutput.Output ?? ""); }); } } }); } catch (Exception e) { Console.WriteLine("[Forerunner] An error occured: {0}", e.Message); } }
// POST: /grunttasking/create public async Task <IActionResult> Create(GruntTasking tasking) { try { CovenantUser currentUser = await _context.GetCurrentUser(_userManager, HttpContext.User); tasking.Grunt = await _context.GetGrunt(tasking.GruntId); tasking.GruntTask = await _context.GetGruntTask(tasking.GruntTaskId); GruntCommand createdCommand = await _context.CreateGruntCommand(new GruntCommand { Command = GetCommand(tasking), CommandTime = DateTime.UtcNow, CommandOutputId = 0, CommandOutput = new CommandOutput(), User = currentUser, GruntId = tasking.Grunt.Id, Grunt = tasking.Grunt }, _grunthub); tasking.GruntCommand = createdCommand; tasking.GruntCommandId = createdCommand.Id; GruntTasking created = await _context.CreateGruntTasking(tasking); return(RedirectToAction(nameof(Interact), new { id = created.Id })); } catch (Exception e) when(e is ControllerNotFoundException || e is ControllerBadRequestException || e is ControllerUnauthorizedException) { return(RedirectToAction(nameof(Index))); } }
public async Task <string> SharpShell(Grunt grunt, GruntCommand command, List <ParsedParameter> parameters) { if (parameters.Count() < 2 || !parameters[0].Value.Equals("SharpShell", StringComparison.OrdinalIgnoreCase)) { return(EliteConsole.PrintFormattedErrorLine("Usage: SharpShell <code>")); } string WrapperFunctionFormat = @"using System; using System.IO; using System.Linq; using System.Text; using System.Security; using System.Security.Principal; using System.Collections.Generic; using SharpSploit.Credentials; using SharpSploit.Enumeration; using SharpSploit.Execution; using SharpSploit.Generic; using SharpSploit.Misc; public static class Task {{ public static string Execute() {{ {0} }} }}"; string csharpcode = string.Join(" ", parameters.Skip(1).Select(P => P.Value).ToArray()); GruntTask newSharpShellTask = await _context.CreateGruntTask(new GruntTask { Name = "SharpShell-" + Utilities.CreateShortGuid(), AlternateNames = new List <string>(), Description = "Execute custom c# code.", Code = string.Format(WrapperFunctionFormat, csharpcode), Options = new List <GruntTaskOption>() }); await _context.AddAsync(new GruntTaskReferenceSourceLibrary { ReferenceSourceLibrary = await _context.GetReferenceSourceLibraryByName("SharpSploit"), GruntTask = newSharpShellTask }); await _context.SaveChangesAsync(); await _context.CreateGruntTasking(new GruntTasking { GruntId = grunt.Id, GruntTaskId = newSharpShellTask.Id, Type = GruntTaskingType.Assembly, Status = GruntTaskingStatus.Uninitialized, GruntCommandId = command.Id, GruntCommand = command }, _grunthub); return(""); }
public async Task <GruntTasking> StartTask(Grunt grunt, GruntTask task, GruntCommand command) { return(await _context.CreateGruntTasking(new GruntTasking { GruntTaskId = task.Id, GruntId = grunt.Id, Type = GruntTaskingType.Assembly, Status = GruntTaskingStatus.Uninitialized, GruntCommandId = command.Id, GruntCommand = command }, _grunthub)); }
public async Task GetInteract(string gruntName, string input) { CovenantUser user = await _service.GetUser(this.Context.UserIdentifier); Grunt grunt = await _service.GetGruntByName(gruntName); GruntCommand command = await _service.InteractGrunt(grunt.Id, user.Id, input); if (!string.IsNullOrWhiteSpace(command.CommandOutput.Output)) { await this.Clients.Caller.SendAsync("ReceiveCommandOutput", command); } }
public async Task GetInteract(string gruntName, string input) { CovenantUser user = await _context.GetUserByUsername(this.Context.User.Identity.Name); Grunt grunt = await _context.GetGruntByName(gruntName); GruntCommand command = await interact.Input(user, grunt, input); if (!string.IsNullOrWhiteSpace(command.CommandOutput.Output)) { await this.Clients.Caller.SendAsync("ReceiveCommandOutput", command); } }
// POST: /grunttasking/create public async Task <IActionResult> Create(GruntTasking tasking) { try { CovenantUser currentUser = await _context.GetCurrentUser(_userManager, HttpContext.User); tasking.Grunt = await _context.GetGrunt(tasking.GruntId); tasking.GruntTask = await _context.GetGruntTask(tasking.GruntTaskId); tasking.Type = tasking.GruntTask.TaskingType; for (int i = 0; i < Math.Min(tasking.Parameters.Count, tasking.GruntTask.Options.Count); i++) { if (tasking.Parameters[i] == null) { tasking.Parameters[i] = ""; tasking.GruntTask.Options[i].Value = ""; } else { tasking.GruntTask.Options[i].Value = tasking.Parameters[i]; } } for (int i = tasking.Parameters.Count; i < tasking.GruntTask.Options.Count; i++) { tasking.GruntTask.Options[i].Value = ""; } GruntCommand createdCommand = await _context.CreateGruntCommand(new GruntCommand { Command = GetCommand(tasking), CommandTime = DateTime.UtcNow, CommandOutputId = 0, CommandOutput = new CommandOutput(), User = currentUser, GruntId = tasking.Grunt.Id, Grunt = tasking.Grunt }, _grunthub, _eventhub); tasking.GruntCommand = createdCommand; tasking.GruntCommandId = createdCommand.Id; GruntTasking created = await _context.CreateGruntTasking(tasking, _grunthub); return(RedirectToAction(nameof(Interact), new { id = created.Id })); } catch (Exception e) when(e is ControllerNotFoundException || e is ControllerBadRequestException || e is ControllerUnauthorizedException) { return(RedirectToAction(nameof(Index))); } }
public async Task GetCommandOutput(int id) { GruntCommand command = await _context.GruntCommands .Where(GC => GC.Id == id) .Include(GC => GC.User) .Include(GC => GC.CommandOutput) .Include(GC => GC.GruntTasking) .ThenInclude(GC => GC.GruntTask) .FirstOrDefaultAsync(); if (!string.IsNullOrWhiteSpace(command.CommandOutput.Output)) { await this.Clients.Caller.SendAsync("ReceiveCommandOutput", command); } }
public async Task GetCommandOutput(int id) { GruntCommand command = await _service.GetGruntCommand(id); command.CommandOutput = command.CommandOutput ?? await _service.GetCommandOutput(command.CommandOutputId); command.User = command.User ?? await _service.GetUser(command.UserId); command.GruntTasking = command.GruntTasking ?? await _service.GetGruntTasking(command.GruntTaskingId ?? default); if (!string.IsNullOrWhiteSpace(command.CommandOutput.Output)) { await this.Clients.Caller.SendAsync("ReceiveCommandOutput", command); } }
public async Task <ActionResult <GruntCommand> > EditGruntCommand([FromBody] GruntCommand gruntCommand) { try { return(await _context.EditGruntCommand(gruntCommand, _grunthub, _eventhub)); } catch (ControllerNotFoundException e) { return(NotFound(e.Message)); } catch (ControllerBadRequestException e) { return(BadRequest(e.Message)); } }
public async Task <string> Disconnect(Grunt grunt, GruntCommand command, List <ParsedParameter> parameters) { string Name = "Disconnect"; StringBuilder toPrint = new StringBuilder(); if (parameters.Count != 2 || !parameters[0].Value.Equals(Name, StringComparison.OrdinalIgnoreCase)) { return(EliteConsole.PrintFormattedErrorLine("Usage: Disconnect <grunt_name>")); } Grunt disconnectGrunt = await _context.Grunts.FirstOrDefaultAsync(G => G.GUID.Equals(parameters[1].Value, StringComparison.OrdinalIgnoreCase)); if (disconnectGrunt == null) { toPrint.Append(EliteConsole.PrintFormattedErrorLine("Invalid GruntName selected: " + parameters[1].Value)); toPrint.Append(EliteConsole.PrintFormattedErrorLine("Usage: Disconnect <grunt_name>")); return(toPrint.ToString()); } List <string> childrenGruntGuids = grunt.Children.ToList(); if (!childrenGruntGuids.Contains(disconnectGrunt.GUID, StringComparer.OrdinalIgnoreCase)) { toPrint.Append(EliteConsole.PrintFormattedErrorLine("Grunt: \"" + parameters[1].Value + "\" is not a child Grunt")); toPrint.Append(EliteConsole.PrintFormattedErrorLine("Usage: Disconnect <grunt_name>")); return(toPrint.ToString()); } GruntTask disconnectTask = await _context.GetGruntTaskByName("Disconnect"); await _context.CreateGruntTasking(new GruntTasking { Id = 0, GruntId = grunt.Id, GruntTaskId = disconnectTask.Id, GruntTask = disconnectTask, Name = Guid.NewGuid().ToString().Replace("-", "").Substring(0, 10), Status = GruntTaskingStatus.Uninitialized, Type = GruntTaskingType.Disconnect, Parameters = new List <string> { disconnectGrunt.GUID }, GruntCommand = command, GruntCommandId = command.Id }, _grunthub); return(toPrint.ToString()); }
public static string GruntExec(string gruntName, string command) { Grunt g = Program.covenantConnection.ApiGruntsByNameGet(gruntName); GruntCommand res = Program.covenantConnection.ApiGruntsByIdInteractPost((int)g.Id, command); Program.tasks.Add(res); int index = Program.tasks.FindIndex(c => c.Id == res.Id); DateTime timeoutTime = DateTime.UtcNow.AddMinutes(60); while (String.IsNullOrEmpty(Program.tasks[index].CommandOutput.Output)) { if (DateTime.Compare(DateTime.UtcNow, timeoutTime) > 0) { return("[Forerunner] Task Failed: No Response"); } } return(Program.tasks[index].CommandOutput.Output); }
public async Task <ActionResult <GruntCommand> > CreateGruntCommand([FromBody] GruntCommand gruntCommand) { try { gruntCommand.Grunt = await _context.GetGrunt(gruntCommand.GruntId); GruntCommand createdCommand = await _context.CreateGruntCommand(gruntCommand, _grunthub, _eventhub); return(CreatedAtRoute(nameof(GetGruntCommand), new { id = createdCommand.Id }, createdCommand)); } catch (ControllerNotFoundException e) { return(NotFound(e.Message)); } catch (ControllerBadRequestException e) { return(BadRequest(e.Message)); } }
public async Task <ActionResult <GruntCommand> > InteractGrunt(int id, [FromBody] string command) { try { CovenantUser user = await _service.GetCurrentUser(this.HttpContext.User); GruntCommand gruntCommand = await _service.InteractGrunt(id, user.Id, command); return(CreatedAtRoute("GetGruntCommand", new { id = gruntCommand.Id }, gruntCommand)); } catch (ControllerNotFoundException e) { return(NotFound(e.Message)); } catch (ControllerBadRequestException e) { return(BadRequest(e.Message)); } }
public static Script GetScript(Grunt g, GruntCommand comm = null) { Script script = new Script(); script.Globals["GruntExec"] = (Func <string, string, string>)GruntHub.GruntExec; script.Globals["WriteToLog"] = (Func <string, string>)WriteToLog; script.Globals["SendSlackNotification"] = (Func <string, string, string, string>)sendSlackNotification; if (!(g is null)) { script.Globals["gruntName"] = g.Name ?? ""; script.Globals["gruntID"] = g.Id.ToString() ?? ""; script.Globals["gruntGUID"] = g.Guid; //script.Globals["gruntListener"] = g.Listener.Name ?? ""; script.Globals["gruntHostname"] = g.Hostname ?? ""; script.Globals["gruntIntegrity"] = g.Integrity.ToString() ?? ""; script.Globals["gruntIP"] = g.IpAddress ?? ""; script.Globals["gruntOS"] = g.OperatingSystem ?? ""; script.Globals["gruntProcess"] = g.Process ?? ""; script.Globals["gruntDomain"] = g.UserDomainName ?? ""; script.Globals["gruntUser"] = g.UserName ?? ""; script.Globals["gruntLastCheckIn"] = g.LastCheckIn.ToString() ?? ""; }
public async static Task SendCommandEvent(IHubContext <GruntHub> context, Event taskingEvent, GruntCommand command) { await context.Clients.Group(taskingEvent.Context).SendAsync("ReceiveCommandEvent", command, taskingEvent); if (taskingEvent.Context != "*") { await context.Clients.Group("*").SendAsync("ReceiveCommandEvent", command, taskingEvent); } }
public async Task NotifyEditGruntCommand(object sender, GruntCommand command) { await Task.Run(() => this.OnEditGruntCommand(sender, command)); }
public async Task <string> Set(Grunt grunt, GruntCommand command, List <ParsedParameter> parameters) { if (parameters.Count != 3) { return(EliteConsole.PrintFormattedErrorLine("Usage: Set (Delay | JitterPercent | ConnectAttempts) <value>")); } if (int.TryParse(parameters[2].Value, out int n)) { GruntTask setTask = await _context.GetGruntTaskByName("Set"); if (parameters[1].Value.Equals("delay", StringComparison.OrdinalIgnoreCase)) { grunt.Delay = n; await _context.CreateGruntTasking(new GruntTasking { Id = 0, GruntId = grunt.Id, Grunt = grunt, GruntTaskId = setTask.Id, GruntTask = setTask, Status = GruntTaskingStatus.Uninitialized, Type = GruntTaskingType.SetDelay, Parameters = new List <string> { grunt.Delay.ToString() }, GruntCommand = command, GruntCommandId = command.Id }, _grunthub); } else if (parameters[1].Value.Equals("jitterpercent", StringComparison.OrdinalIgnoreCase)) { grunt.JitterPercent = n; await _context.CreateGruntTasking(new GruntTasking { Id = 0, GruntId = grunt.Id, Grunt = grunt, GruntTaskId = setTask.Id, GruntTask = setTask, Status = GruntTaskingStatus.Uninitialized, Type = GruntTaskingType.SetJitter, Parameters = new List <string> { grunt.JitterPercent.ToString() }, GruntCommand = command, GruntCommandId = command.Id }, _grunthub); } else if (parameters[1].Value.Equals("connectattempts", StringComparison.OrdinalIgnoreCase)) { grunt.ConnectAttempts = n; await _context.CreateGruntTasking(new GruntTasking { Id = 0, GruntId = grunt.Id, Grunt = grunt, GruntTaskId = setTask.Id, GruntTask = setTask, Status = GruntTaskingStatus.Uninitialized, Type = GruntTaskingType.SetConnectAttempts, Parameters = new List <string> { grunt.ConnectAttempts.ToString() }, GruntCommand = command, GruntCommandId = command.Id }, _grunthub); } return(""); } return(EliteConsole.PrintFormattedErrorLine("Usage: Set (Delay | JitterPercent | ConnectAttempts) <value>")); }
public Task <GruntCommand> CreateGruntCommand(GruntCommand command) { return(_connection.InvokeAsync <GruntCommand>("CreateGruntCommand", command)); }
public Task <GruntCommand> EditGruntCommand(GruntCommand command) { return(_connection.InvokeAsync <GruntCommand>("EditGruntCommand", command)); }
public async Task <GruntCommand> Input(CovenantUser user, Grunt grunt, string UserInput) { GruntCommand GruntCommand = await _context.CreateGruntCommand(new GruntCommand { Command = GetCommandFromInput(UserInput), CommandTime = DateTime.UtcNow, User = user, GruntId = grunt.Id, Grunt = grunt, CommandOutputId = 0, CommandOutput = new CommandOutput() }, _grunthub, _eventhub); List <ParsedParameter> parameters = ParseParameters(UserInput).ToList(); GruntTask commandTask = null; try { commandTask = await _context.GetGruntTaskByName(parameters.FirstOrDefault().Value); if (commandTask.Options.Count == 1 && new List <string> { "Command", "ShellCommand", "PowerShellCommand", "Code" }.Contains(commandTask.Options[0].Name)) { parameters = new List <ParsedParameter> { new ParsedParameter { Value = commandTask.Name, Label = "", IsLabeled = false, Position = 0 }, new ParsedParameter { Value = UserInput.Substring(UserInput.IndexOf(" ", StringComparison.Ordinal) + 1).Trim('"'), Label = "", IsLabeled = false, Position = 0 } }; } } catch (ControllerNotFoundException) { } string output = ""; if (parameters.FirstOrDefault().Value.ToLower() == "show") { output = await Show(grunt); } else if (parameters.FirstOrDefault().Value.ToLower() == "help") { output = await Help(parameters); } else if (parameters.FirstOrDefault().Value.ToLower() == "sharpshell") { output = await SharpShell(grunt, GruntCommand, parameters); } else if (parameters.FirstOrDefault().Value.ToLower() == "kill") { output = await Kill(grunt, GruntCommand, parameters); } else if (parameters.FirstOrDefault().Value.ToLower() == "set") { output = await Set(grunt, GruntCommand, parameters); } else if (parameters.FirstOrDefault().Value.ToLower() == "history") { output = await History(grunt, parameters); } else if (parameters.FirstOrDefault().Value.ToLower() == "connect") { output = await Connect(grunt, GruntCommand, parameters); } else if (parameters.FirstOrDefault().Value.ToLower() == "disconnect") { output = await Disconnect(grunt, GruntCommand, parameters); } else if (parameters.FirstOrDefault().Value.ToLower() == "jobs") { output = await Jobs(grunt, GruntCommand, parameters); } else if (parameters.FirstOrDefault().Value.ToLower() == "note") { grunt.Note = string.Join(" ", parameters.Skip(1).Select(P => P.Value).ToArray()); await _context.EditGrunt(grunt, user, _grunthub, _eventhub); output = "Note: " + grunt.Note; } else if (parameters.FirstOrDefault().Value.ToLower() == "powershellimport") { grunt.PowerShellImport = parameters.Count >= 2 ? parameters[1].Value : ""; await _context.EditGrunt(grunt, user, _grunthub, _eventhub); output = "PowerShell Imported"; } else if (commandTask != null) { parameters = parameters.Skip(1).ToList(); if (parameters.Count() < commandTask.Options.Count(O => !O.Optional)) { _context.Entry(GruntCommand).State = EntityState.Detached; GruntCommand.CommandOutput.Output = EliteConsole.PrintFormattedErrorLine(GetUsage(commandTask)); return(await _context.EditGruntCommand(GruntCommand, _grunthub, _eventhub)); } // All options begin unassigned List <bool> OptionAssignments = commandTask.Options.Select(O => false).ToList(); commandTask.Options.ForEach(O => O.Value = ""); for (int i = 0; i < parameters.Count; i++) { if (parameters[i].IsLabeled) { var option = commandTask.Options.FirstOrDefault(O => O.Name.Equals(parameters[i].Label, StringComparison.OrdinalIgnoreCase)); option.Value = parameters[i].Value; OptionAssignments[commandTask.Options.IndexOf(option)] = true; } else { GruntTaskOption nextOption = null; // Find next unassigned option for (int j = 0; j < commandTask.Options.Count; j++) { if (!OptionAssignments[j]) { nextOption = commandTask.Options[j]; OptionAssignments[j] = true; break; } } if (nextOption == null) { // This is an extra parameter _context.Entry(GruntCommand).State = EntityState.Detached; GruntCommand.CommandOutput.Output = EliteConsole.PrintFormattedErrorLine(GetUsage(commandTask)); return(await _context.EditGruntCommand(GruntCommand, _grunthub, _eventhub)); } nextOption.Value = parameters[i].Value; } } // Check for unassigned required options for (int i = 0; i < commandTask.Options.Count; i++) { if (!OptionAssignments[i] && !commandTask.Options[i].Optional) { // This is an extra parameter StringBuilder toPrint = new StringBuilder(); toPrint.Append(EliteConsole.PrintFormattedErrorLine(commandTask.Options[i].Name + " is required.")); toPrint.Append(EliteConsole.PrintFormattedErrorLine(GetUsage(commandTask))); _context.Entry(GruntCommand).State = EntityState.Detached; GruntCommand.CommandOutput.Output = toPrint.ToString(); return(await _context.EditGruntCommand(GruntCommand, _grunthub, _eventhub)); } } // Parameters have parsed successfully commandTask = await _context.EditGruntTask(commandTask); await StartTask(grunt, commandTask, GruntCommand); } else { output = EliteConsole.PrintFormattedErrorLine("Unrecognized command"); } _context.Entry(GruntCommand).State = EntityState.Detached; GruntCommand.CommandOutput.Output = output; return(await _context.EditGruntCommand(GruntCommand, _grunthub, _eventhub)); }