public async Task <int> ExecuteCommand(CommandSettings command) { ArgUtil.NotNull(command, nameof(command)); try { var agentWebProxy = HostContext.GetService <IVstsAgentWebProxy>(); var agentCertManager = HostContext.GetService <IAgentCertificateManager>(); VssUtil.InitializeVssClientSettings(HostContext.UserAgent, agentWebProxy.WebProxy, agentCertManager.VssClientCertificateManager); _inConfigStage = true; _completedCommand.Reset(); _term.CancelKeyPress += CtrlCHandler; //register a SIGTERM handler HostContext.Unloading += Agent_Unloading; // TODO Unit test to cover this logic Trace.Info(nameof(ExecuteCommand)); var configManager = HostContext.GetService <IConfigurationManager>(); // command is not required, if no command it just starts if configured // TODO: Invalid config prints usage if (command.IsHelp()) { PrintUsage(command); return(Constants.Agent.ReturnCode.Success); } if (command.IsVersion()) { _term.WriteLine(BuildConstants.AgentPackage.Version); return(Constants.Agent.ReturnCode.Success); } if (command.IsCommit()) { _term.WriteLine(BuildConstants.Source.CommitHash); return(Constants.Agent.ReturnCode.Success); } if (command.IsDiagnostics()) { PrintBanner(); _term.WriteLine("Running Diagnostics Only..."); _term.WriteLine(string.Empty); DiagnosticTests diagnostics = new DiagnosticTests(_term); diagnostics.Execute(); return(Constants.Agent.ReturnCode.Success); } // Configure agent prompt for args if not supplied // Unattend configure mode will not prompt for args if not supplied and error on any missing or invalid value. if (command.IsConfigureCommand()) { PrintBanner(); try { await configManager.ConfigureAsync(command); return(Constants.Agent.ReturnCode.Success); } catch (Exception ex) { Trace.Error(ex); _term.WriteError(ex.Message); return(Constants.Agent.ReturnCode.TerminatedError); } } // remove config files, remove service, and exit if (command.IsRemoveCommand()) { try { await configManager.UnconfigureAsync(command); return(Constants.Agent.ReturnCode.Success); } catch (Exception ex) { Trace.Error(ex); _term.WriteError(ex.Message); return(Constants.Agent.ReturnCode.TerminatedError); } } _inConfigStage = false; // warmup agent process (JIT/CLR) // In scenarios where the agent is single use (used and then thrown away), the system provisioning the agent can call `agent.listener --warmup` before the machine is made available to the pool for use. // this will optimizes the agent process startup time. if (command.IsWarmupCommand()) { var binDir = HostContext.GetDirectory(WellKnownDirectory.Bin); foreach (var assemblyFile in Directory.EnumerateFiles(binDir, "*.dll")) { try { Trace.Info($"Load assembly: {assemblyFile}."); var assembly = Assembly.LoadFrom(assemblyFile); var types = assembly.GetTypes(); foreach (Type loadedType in types) { try { Trace.Info($"Load methods: {loadedType.FullName}."); var methods = loadedType.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); foreach (var method in methods) { if (!method.IsAbstract && !method.ContainsGenericParameters) { Trace.Verbose($"Prepare method: {method.Name}."); RuntimeHelpers.PrepareMethod(method.MethodHandle); } } } catch (Exception ex) { Trace.Error(ex); } } } catch (Exception ex) { Trace.Error(ex); } } return(Constants.Agent.ReturnCode.Success); } AgentSettings settings = configManager.LoadSettings(); var store = HostContext.GetService <IConfigurationStore>(); bool configuredAsService = store.IsServiceConfigured(); // Run agent //if (command.Run) // this line is current break machine provisioner. //{ // Error if agent not configured. if (!configManager.IsConfigured()) { _term.WriteError(StringUtil.Loc("AgentIsNotConfigured")); PrintUsage(command); return(Constants.Agent.ReturnCode.TerminatedError); } Trace.Verbose($"Configured as service: '{configuredAsService}'"); //Get the startup type of the agent i.e., autostartup, service, manual StartupType startType; var startupTypeAsString = command.GetStartupType(); if (string.IsNullOrEmpty(startupTypeAsString) && configuredAsService) { // We need try our best to make the startup type accurate // The problem is coming from agent autoupgrade, which result an old version service host binary but a newer version agent binary // At that time the servicehost won't pass --startuptype to agent.listener while the agent is actually running as service. // We will guess the startup type only when the agent is configured as service and the guess will based on whether STDOUT/STDERR/STDIN been redirect or not Trace.Info($"Try determine agent startup type base on console redirects."); startType = (Console.IsErrorRedirected && Console.IsInputRedirected && Console.IsOutputRedirected) ? StartupType.Service : StartupType.Manual; } else { if (!Enum.TryParse(startupTypeAsString, true, out startType)) { Trace.Info($"Could not parse the argument value '{startupTypeAsString}' for StartupType. Defaulting to {StartupType.Manual}"); startType = StartupType.Manual; } } Trace.Info($"Set agent startup type - {startType}"); HostContext.StartupType = startType; if (PlatformUtil.RunningOnWindows) { if (store.IsAutoLogonConfigured()) { if (HostContext.StartupType != StartupType.Service) { Trace.Info($"Autologon is configured on the machine, dumping all the autologon related registry settings"); var autoLogonRegManager = HostContext.GetService <IAutoLogonRegistryManager>(); autoLogonRegManager.DumpAutoLogonRegistrySettings(); } else { Trace.Info($"Autologon is configured on the machine but current Agent.Listner.exe is launched from the windows service"); } } } // Run the agent interactively or as service return(await RunAsync(settings, command.GetRunOnce())); } finally { _term.CancelKeyPress -= CtrlCHandler; HostContext.Unloading -= Agent_Unloading; _completedCommand.Set(); } }