public void ConfigureService(AgentSettings settings, CommandSettings command) { Trace.Entering(); // TODO: Fix bug that exists in the legacy Windows agent where configuration using mirrored credentials causes an error, but the agent is still functional (after restarting). Mirrored credentials is a supported scenario and shouldn't manifest any errors. // We use NetworkService as default account. NTAccount defaultServiceAccount = _windowsServiceHelper.GetDefaultServiceAccount(); _logonAccount = command.GetWindowsLogonAccount(defaultValue: defaultServiceAccount.ToString()); NativeWindowsServiceHelper.GetAccountSegments(_logonAccount, out _domainName, out _userName); if ((string.IsNullOrEmpty(_domainName) || _domainName.Equals(".", StringComparison.CurrentCultureIgnoreCase)) && !_logonAccount.Contains('@')) { _logonAccount = String.Format("{0}\\{1}", Environment.MachineName, _userName); } Trace.Info("LogonAccount after transforming: {0}, user: {1}, domain: {2}", _logonAccount, _userName, _domainName); string logonPassword = string.Empty; if (!defaultServiceAccount.Equals(new NTAccount(_logonAccount)) && !NativeWindowsServiceHelper.IsWellKnownIdentity(_logonAccount)) { while (true) { logonPassword = command.GetWindowsLogonPassword(_logonAccount); if (_windowsServiceHelper.IsValidCredential(_domainName, _userName, logonPassword)) { Trace.Info("Credential validation succeed"); break; } else { if (!command.Unattended) { Trace.Info("Invalid credential entered"); _term.WriteLine(StringUtil.Loc("InvalidWindowsCredential")); } else { throw new SecurityException(StringUtil.Loc("InvalidWindowsCredential")); } } } } string serviceName; string serviceDisplayName; CalculateServiceName(settings, ServiceNamePattern, ServiceDisplayNamePattern, out serviceName, out serviceDisplayName); if (CheckServiceExists(serviceName)) { _term.WriteLine(StringUtil.Loc("ServiceAlreadyExists", serviceName)); UninstallService(serviceName); } Trace.Info("Verifying if the account has LogonAsService permission"); if (!_windowsServiceHelper.CheckUserHasLogonAsServicePrivilege(_domainName, _userName)) { Trace.Info($"Account: {_logonAccount} already has Logon As Service Privilege."); } else { if (!_windowsServiceHelper.GrantUserLogonAsServicePrivilage(_domainName, _userName)) { throw new InvalidOperationException(StringUtil.Loc("CanNotGrantPermission", _logonAccount)); } } Trace.Info("Create local group and grant folder permission to service logon account."); GrantDirectoryPermissionForAccount(); // install service. _windowsServiceHelper.InstallService(serviceName, serviceDisplayName, _logonAccount, logonPassword); // create .service file with service name. SaveServiceSettings(serviceName); // Add registry key after installation _windowsServiceHelper.CreateVstsAgentRegistryKey(); Trace.Info("Configuration was successful, trying to start the service"); StartService(serviceName); }
public override bool ConfigureService(AgentSettings settings, CommandSettings command) { Trace.Entering(); // TODO: add entering with info level. By default the error leve would be info. Config changes can get lost with this as entering is at Verbose level. For config all the logs should be logged. // TODO: Fix bug that exists in the legacy Windows agent where configuration using mirrored credentials causes an error, but the agent is still functional (after restarting). Mirrored credentials is a supported scenario and shouldn't manifest any errors. string logonPassword = string.Empty; NTAccount defaultServiceAccount = _windowsServiceHelper.GetDefaultServiceAccount(); _logonAccount = command.GetWindowsLogonAccount(defaultValue: defaultServiceAccount.ToString()); NativeWindowsServiceHelper.GetAccountSegments(_logonAccount, out _domainName, out _userName); if ((string.IsNullOrEmpty(_domainName) || _domainName.Equals(".", StringComparison.CurrentCultureIgnoreCase)) && !_logonAccount.Contains('@')) { _logonAccount = String.Format("{0}\\{1}", Environment.MachineName, _userName); } Trace.Info("LogonAccount after transforming: {0}, user: {1}, domain: {2}", _logonAccount, _userName, _domainName); if (!defaultServiceAccount.Equals(new NTAccount(_logonAccount)) && !NativeWindowsServiceHelper.IsWellKnownIdentity(_logonAccount)) { while (true) { logonPassword = command.GetWindowsLogonPassword(_logonAccount); // TODO: Fix this for unattended (should throw if not valid). // TODO: If account is locked there is no point in retrying, translate error to useful message if (_windowsServiceHelper.IsValidCredential(_domainName, _userName, logonPassword) || command.Unattended) { break; } Trace.Info("Invalid credential entered"); _term.WriteLine(StringUtil.Loc("InvalidWindowsCredential")); } } CalculateServiceName(settings, ServiceNamePattern, ServiceDisplayNamePattern); if (CheckServiceExists(ServiceName)) { _term.WriteLine(StringUtil.Loc("ServiceAleadyExists")); StopService(); UninstallService(ServiceName); } Trace.Info("Verifying if the account has LogonAsService permission"); if (!_windowsServiceHelper.CheckUserHasLogonAsServicePrivilege(_domainName, _userName)) { Trace.Info(StringUtil.Format("Account: {0} already has Logon As Service Privilege.", _logonAccount)); } else { if (!_windowsServiceHelper.GrantUserLogonAsServicePrivilage(_domainName, _userName)) { throw new InvalidOperationException(StringUtil.Loc("CanNotGrantPermission", _logonAccount)); } } _windowsServiceHelper.InstallService(ServiceName, ServiceDisplayName, _logonAccount, logonPassword); SaveServiceSettings(); // TODO: If its service identity add it to appropriate PoolGroup // Add registry key after installation _windowsServiceHelper.CreateVstsAgentRegistryKey(); return(true); }
public override bool ConfigureService(AgentSettings settings, Dictionary <string, string> args, bool enforceSupplied) { Trace.Entering(); // TODO: add entering with info level. By default the error leve would be info. Config changes can get lost with this as entering is at Verbose level. For config all the logs should be logged. // TODO: Fix bug that exists in the legacy Windows agent where configuration using mirrored credentials causes an error, but the agent is still functional (after restarting). Mirrored credentials is a supported scenario and shouldn't manifest any errors. var consoleWizard = HostContext.GetService <IConsoleWizard>(); string logonPassword = string.Empty; NTAccount defaultServiceAccount = _windowsServiceHelper.GetDefaultServiceAccount(); _logonAccount = consoleWizard.ReadValue(WindowsLogonAccount, StringUtil.Loc("WindowsLogonAccountNameDescription"), false, defaultServiceAccount.ToString(), Validators.NTAccountValidator, args, enforceSupplied); Trace.Info("Received LogonAccount: {0}", _logonAccount); NativeWindowsServiceHelper.GetAccountSegments(_logonAccount, out _domainName, out _userName); if ((string.IsNullOrEmpty(_domainName) || _domainName.Equals(".", StringComparison.CurrentCultureIgnoreCase)) && !_logonAccount.Contains('@')) { _logonAccount = String.Format("{0}\\{1}", Environment.MachineName, _userName); } Trace.Info("LogonAccount after transforming: {0}, user: {1}, domain: {2}", _logonAccount, _userName, _domainName); if (!defaultServiceAccount.Equals(new NTAccount(_logonAccount))) { while (true) { Trace.Info("Acquiring logon account password"); logonPassword = consoleWizard.ReadValue(WindowsLogonPassword, StringUtil.Loc("WindowsLogonPasswordDescription", _logonAccount), true, string.Empty, Validators.NonEmptyValidator, args, enforceSupplied); // TODO: If account is locked there is no point in retrying, translate error to useful message if (_windowsServiceHelper.IsValidCredential(_domainName, _userName, logonPassword) || enforceSupplied) { break; } Trace.Info("Invalid credential entered"); _term.WriteLine(StringUtil.Loc("InvalidWindowsCredential")); } } CalculateServiceName(settings, ServiceNamePattern, ServiceDisplayNamePattern); if (CheckServiceExists(settings.ServiceName)) { _term.WriteLine(StringUtil.Loc("ServiceAleadyExists")); StopService(settings.ServiceName); UninstallService(settings.ServiceName); } Trace.Info("Verifying if the account has LogonAsService permission"); if (!_windowsServiceHelper.CheckUserHasLogonAsServicePrivilege(_domainName, _userName)) { Trace.Info(StringUtil.Format("Account: {0} already has Logon As Service Privilege.", _logonAccount)); } else { if (!_windowsServiceHelper.GrantUserLogonAsServicePrivilage(_domainName, _userName)) { throw new InvalidOperationException(StringUtil.Loc("CanNotGrantPermission", _logonAccount)); } } _windowsServiceHelper.InstallService(settings.ServiceName, settings.ServiceDisplayName, _logonAccount, logonPassword); // TODO: If its service identity add it to appropriate PoolGroup // TODO: Add registry key after installation return(true); }