From 1d069115455d43cd9b27a22540209d87a1dfa100 Mon Sep 17 00:00:00 2001 From: Mike Mooney Date: Sun, 3 Nov 2013 14:59:15 -0500 Subject: [PATCH 1/5] Add WMI credentials for WinService --- .../WinService/WinTestsWithAuthentication.cs | 121 ++++++++++++++++++ product/dropkick.tests/dropkick.tests.csproj | 1 + .../Configuration/Dsl/WinService/Extension.cs | 2 +- .../WinService/ProtoWinServiceCreateTask.cs | 11 +- .../WinService/ProtoWinServiceDeleteTask.cs | 8 +- .../WinService/ProtoWinServiceStartTask.cs | 8 +- .../Dsl/WinService/ProtoWinServiceStopTask.cs | 8 +- .../Dsl/WinService/ProtoWinServiceTask.cs | 20 ++- .../Dsl/WinService/WinServiceOptions.cs | 1 + .../Tasks/WinService/BaseServiceTask.cs | 61 ++++++++- .../Tasks/WinService/WinServiceCreateTask.cs | 12 +- .../Tasks/WinService/WinServiceDeleteTask.cs | 25 +++- .../Tasks/WinService/WinServiceStartTask.cs | 76 ++++++++--- .../Tasks/WinService/WinServiceStopTask.cs | 50 ++++++-- product/dropkick/Wmi/WmiHelper.cs | 55 ++++++-- product/dropkick/Wmi/WmiService.cs | 20 +-- 16 files changed, 405 insertions(+), 74 deletions(-) create mode 100644 product/dropkick.tests/Tasks/WinService/WinTestsWithAuthentication.cs diff --git a/product/dropkick.tests/Tasks/WinService/WinTestsWithAuthentication.cs b/product/dropkick.tests/Tasks/WinService/WinTestsWithAuthentication.cs new file mode 100644 index 00000000..087c4502 --- /dev/null +++ b/product/dropkick.tests/Tasks/WinService/WinTestsWithAuthentication.cs @@ -0,0 +1,121 @@ +using dropkick.DeploymentModel; +using dropkick.Tasks.WinService; +using dropkick.Wmi; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Xml.Serialization; + +namespace dropkick.tests.Tasks.WinService +{ + [TestFixture] + [Category("Integration")] + public class WinTestsWithAuthentication + { + public class WmiAuthenticationInfo + { + public string MachineName { get; set; } + public string WmiUserName { get; set; } + public string WmiPassword { get; set; } + public string ServiceUserName { get; set; } + public string ServicePassword { get; set; } + } + + private WmiAuthenticationInfo GetAuthenticationInfo() + { + string path = System.IO.Path.GetFullPath("WmiAuthenticationInfo.xml"); + if (!System.IO.File.Exists(path)) + { + throw new Exception("Please create a settings file first at: " + path); + } + var serializer = new XmlSerializer(typeof(WmiAuthenticationInfo)); + using (var reader = new System.IO.StreamReader(path)) + { + return (WmiAuthenticationInfo)serializer.Deserialize(reader); + } + } + + [Test] + [Explicit] + [Category("Integration")] + public void Start() + { + var authInfo = GetAuthenticationInfo(); + + var t = new WinServiceStopTask(authInfo.MachineName, "IISADMIN", authInfo.WmiUserName, authInfo.WmiPassword); + var verifyStopResult = t.VerifyCanRun(); + Log(verifyStopResult); + AssertSuccess(verifyStopResult); + + var stopResult = t.Execute(); + Log(stopResult); + AssertSuccess(stopResult); + + var t2 = new WinServiceStartTask(authInfo.MachineName, "IISADMIN", authInfo.WmiUserName, authInfo.WmiPassword); + var verifyStartResult = t2.VerifyCanRun(); + Log(verifyStartResult); + AssertSuccess(verifyStartResult); + + var startResult = t2.Execute(); + Log(startResult); + AssertSuccess(startResult); + } + + [Test] + [Explicit] + public void RemoteCreate() + { + var authInfo = GetAuthenticationInfo(); + + var t = new WinServiceCreateTask(authInfo.MachineName, "DropKicKTestService", authInfo.WmiUserName, authInfo.WmiPassword); + + t.ServiceLocation = "C:\\Test\\TestService.exe"; + t.StartMode = ServiceStartMode.Automatic; + t.UserName = authInfo.ServiceUserName; + t.Password = authInfo.ServicePassword; + + DeploymentResult o = t.VerifyCanRun(); + AssertSuccess(o); + var result = t.Execute(); + Log(result); + AssertSuccess(result); + } + + [Test] + [Explicit] + [Category("Integration")] + public void RemoteDelete() + { + var authInfo = GetAuthenticationInfo(); + + var t = new WinServiceDeleteTask(authInfo.MachineName, "DropkicKTestService", authInfo.ServiceUserName, authInfo.ServicePassword); + + DeploymentResult o = t.VerifyCanRun(); + Log(o); + AssertSuccess(o); + var result = t.Execute(); + Log(result); + AssertSuccess(result); + } + + private void AssertSuccess(DeploymentResult result) + { + Assert.IsFalse(result.Any(i => i.Status == DeploymentItemStatus.Alert || i.Status == DeploymentItemStatus.Error)); + } + + private void Log(DeploymentResult result) + { + if(result != null) + { + foreach(var item in result) + { + Debug.WriteLine(item.Message); + } + } + } + + } +} diff --git a/product/dropkick.tests/dropkick.tests.csproj b/product/dropkick.tests/dropkick.tests.csproj index 902aaa25..afa676b5 100644 --- a/product/dropkick.tests/dropkick.tests.csproj +++ b/product/dropkick.tests/dropkick.tests.csproj @@ -138,6 +138,7 @@ + diff --git a/product/dropkick/Configuration/Dsl/WinService/Extension.cs b/product/dropkick/Configuration/Dsl/WinService/Extension.cs index e6db68e3..7554592d 100644 --- a/product/dropkick/Configuration/Dsl/WinService/Extension.cs +++ b/product/dropkick/Configuration/Dsl/WinService/Extension.cs @@ -17,6 +17,6 @@ public static class Extension public static WinServiceOptions WinService(this ProtoServer protoServer, string serviceName) { return new ProtoWinServiceTask(protoServer, serviceName); - } + } } } \ No newline at end of file diff --git a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceCreateTask.cs b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceCreateTask.cs index 5add6935..9f15791b 100644 --- a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceCreateTask.cs +++ b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceCreateTask.cs @@ -33,6 +33,8 @@ public class ProtoWinServiceCreateTask : ServiceStartMode _startMode; string _userName; Path _path; + string _wmiUserName; + string _wmiPassword; public ProtoWinServiceCreateTask(Path path, string serviceName) { @@ -58,6 +60,13 @@ public WinServiceCreateOptions WithStartMode(ServiceStartMode mode) return this; } + public WinServiceCreateOptions WithAuthentication(string userName, string password) + { + _wmiUserName = userName; + _wmiPassword = password; + return this; + } + public WinServiceCreateOptions WithCredentials(string username, string password) { _userName = ReplaceTokens(username); @@ -78,7 +87,7 @@ public override void RegisterRealTasks(PhysicalServer site) string serviceLocation = _installPath; serviceLocation = _path.GetPhysicalPath(site, _installPath, true); - site.AddTask(new WinServiceCreateTask(site.Name, _serviceName) + site.AddTask(new WinServiceCreateTask(site.Name, _serviceName, _wmiUserName, _wmiPassword) { Dependencies = _dependencies.ToArray(), UserName = _userName, diff --git a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceDeleteTask.cs b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceDeleteTask.cs index 48ed94d2..a83651e3 100644 --- a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceDeleteTask.cs +++ b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceDeleteTask.cs @@ -20,15 +20,19 @@ public class ProtoWinServiceDeleteTask : BaseProtoTask { readonly string _serviceName; + readonly string _wmiUserName; + readonly string _wmiPassword; - public ProtoWinServiceDeleteTask(string serviceName) + public ProtoWinServiceDeleteTask(string serviceName, string wmiUserName=null, string wmiPassword=null) { _serviceName = ReplaceTokens(serviceName); + _wmiUserName = ReplaceTokens(wmiUserName); + _wmiPassword = ReplaceTokens(wmiPassword); } public override void RegisterRealTasks(PhysicalServer site) { - site.AddTask(new WinServiceDeleteTask(site.Name, _serviceName)); + site.AddTask(new WinServiceDeleteTask(site.Name, _serviceName, _wmiUserName, _wmiPassword)); } } } \ No newline at end of file diff --git a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStartTask.cs b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStartTask.cs index bc508456..27b5e107 100644 --- a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStartTask.cs +++ b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStartTask.cs @@ -20,15 +20,19 @@ public class ProtoWinServiceStartTask : BaseProtoTask { readonly string _serviceName; + readonly string _wmiUserName; + readonly string _wmiPassword; - public ProtoWinServiceStartTask(string serviceName) + public ProtoWinServiceStartTask(string serviceName, string wmiUserName=null, string wmiPassword=null) { _serviceName = ReplaceTokens(serviceName); + _wmiUserName = ReplaceTokens(wmiUserName); + _wmiPassword = ReplaceTokens(wmiPassword); } public override void RegisterRealTasks(PhysicalServer s) { - s.AddTask(new WinServiceStartTask(s.Name, _serviceName)); + s.AddTask(new WinServiceStartTask(s.Name, _serviceName, _wmiUserName, _wmiPassword)); } } } \ No newline at end of file diff --git a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStopTask.cs b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStopTask.cs index acecf999..f90748f8 100644 --- a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStopTask.cs +++ b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStopTask.cs @@ -20,15 +20,19 @@ public class ProtoWinServiceStopTask : BaseProtoTask { readonly string _serviceName; + readonly string _wmiUserName; + readonly string _wmiPassword; - public ProtoWinServiceStopTask(string serviceName) + public ProtoWinServiceStopTask(string serviceName, string wmiUserName=null, string wmiPassword=null) { _serviceName = ReplaceTokens(serviceName); + _wmiUserName = ReplaceTokens(wmiUserName); + _wmiPassword = ReplaceTokens(wmiPassword); } public override void RegisterRealTasks(PhysicalServer s) { - s.AddTask(new WinServiceStopTask(s.Name, _serviceName)); + s.AddTask(new WinServiceStopTask(s.Name, _serviceName, _wmiUserName, _wmiPassword)); } } } \ No newline at end of file diff --git a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceTask.cs b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceTask.cs index 9e524782..de44cf11 100644 --- a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceTask.cs +++ b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceTask.cs @@ -20,6 +20,8 @@ public class ProtoWinServiceTask : { readonly ProtoServer _protoServer; readonly string _serviceName; + string _wmiUserName; + string _wmiPassword; public ProtoWinServiceTask(ProtoServer protoServer, string serviceName) { @@ -27,28 +29,34 @@ public ProtoWinServiceTask(ProtoServer protoServer, string serviceName) _serviceName = serviceName; } + public WinServiceOptions WithAuthentication(string wmiUserName, string wmiPassword) + { + _wmiUserName = wmiUserName; + _wmiPassword = wmiPassword; + return this; + } public WinServiceOptions Do(Action registerAdditionalActions) { - _protoServer.RegisterProtoTask(new ProtoWinServiceStopTask(_serviceName)); + _protoServer.RegisterProtoTask(new ProtoWinServiceStopTask(_serviceName, _wmiUserName, _wmiPassword)); //child task registerAdditionalActions(_protoServer); - - _protoServer.RegisterProtoTask(new ProtoWinServiceStartTask(_serviceName)); + + _protoServer.RegisterProtoTask(new ProtoWinServiceStartTask(_serviceName, _wmiUserName, _wmiPassword)); return this; } public void Start() { - _protoServer.RegisterProtoTask(new ProtoWinServiceStartTask(_serviceName)); + _protoServer.RegisterProtoTask(new ProtoWinServiceStartTask(_serviceName, _wmiUserName, _wmiPassword)); } public void Stop() { - _protoServer.RegisterProtoTask(new ProtoWinServiceStopTask(_serviceName)); + _protoServer.RegisterProtoTask(new ProtoWinServiceStopTask(_serviceName, _wmiUserName, _wmiPassword)); } public WinServiceCreateOptions Create() @@ -60,7 +68,7 @@ public WinServiceCreateOptions Create() public void Delete() { - _protoServer.RegisterProtoTask(new ProtoWinServiceDeleteTask(_serviceName)); + _protoServer.RegisterProtoTask(new ProtoWinServiceDeleteTask(_serviceName, _wmiUserName, _wmiPassword)); } } } \ No newline at end of file diff --git a/product/dropkick/Configuration/Dsl/WinService/WinServiceOptions.cs b/product/dropkick/Configuration/Dsl/WinService/WinServiceOptions.cs index 7329c51b..ce832547 100644 --- a/product/dropkick/Configuration/Dsl/WinService/WinServiceOptions.cs +++ b/product/dropkick/Configuration/Dsl/WinService/WinServiceOptions.cs @@ -20,6 +20,7 @@ public interface WinServiceOptions void Stop(); WinServiceCreateOptions Create(); void Delete(); + WinServiceOptions WithAuthentication(string userName, string password); WinServiceOptions Do(Action registerAdditionalActions); } } \ No newline at end of file diff --git a/product/dropkick/Tasks/WinService/BaseServiceTask.cs b/product/dropkick/Tasks/WinService/BaseServiceTask.cs index bc687fb9..5f00ebac 100644 --- a/product/dropkick/Tasks/WinService/BaseServiceTask.cs +++ b/product/dropkick/Tasks/WinService/BaseServiceTask.cs @@ -19,24 +19,77 @@ namespace dropkick.Tasks.WinService public abstract class BaseServiceTask : BaseTask { - protected BaseServiceTask(string machineName, string serviceName) + protected BaseServiceTask(string machineName, string serviceName, string wmiUserName, string wmiPassword) { MachineName = machineName; ServiceName = serviceName; + WmiUserName = wmiUserName; + WmiPassword = wmiPassword; } public string MachineName { get; set; } public string ServiceName { get; set; } + public string WmiUserName { get; set; } + public string WmiPassword { get; set; } + protected bool ServiceIsRunning() + { + try + { + if (string.IsNullOrEmpty(WmiUserName) || string.IsNullOrEmpty(WmiPassword)) + { + using (var c = new ServiceController(ServiceName, MachineName)) + { + return (c.Status == ServiceControllerStatus.Running); + } + } + else + { + var status = dropkick.Wmi.WmiService.QueryService(MachineName, ServiceName, WmiUserName, WmiPassword); + switch (status) + { + case Wmi.ServiceReturnCode.ServiceAlreadyRunning: + case Wmi.ServiceReturnCode.Success: + return true; + default: + return false; + } + } + } + catch (Exception) + { + return false; + } + } protected bool ServiceExists() { try { - using (var c = new ServiceController(ServiceName, MachineName)) + if(string.IsNullOrEmpty(WmiUserName) || string.IsNullOrEmpty(WmiPassword)) + { + using (var c = new ServiceController(ServiceName, MachineName)) + { + ServiceControllerStatus currentStatus = c.Status; + return true; + } + } + else { - ServiceControllerStatus currentStatus = c.Status; - return true; + var status = dropkick.Wmi.WmiService.QueryService(MachineName, ServiceName, WmiUserName, WmiPassword); + switch(status) + { + case Wmi.ServiceReturnCode.DependentServicesRunning: + case Wmi.ServiceReturnCode.ServiceAlreadyPaused: + case Wmi.ServiceReturnCode.ServiceAlreadyRunning: + case Wmi.ServiceReturnCode.StatusServiceExists: + case Wmi.ServiceReturnCode.Success: + case Wmi.ServiceReturnCode.ServiceNotActive: + case Wmi.ServiceReturnCode.InvalidServiceControl: + return true; + default: + return false; + } } } catch (Exception) diff --git a/product/dropkick/Tasks/WinService/WinServiceCreateTask.cs b/product/dropkick/Tasks/WinService/WinServiceCreateTask.cs index ceedb5d2..c42dbe62 100644 --- a/product/dropkick/Tasks/WinService/WinServiceCreateTask.cs +++ b/product/dropkick/Tasks/WinService/WinServiceCreateTask.cs @@ -24,8 +24,8 @@ public class WinServiceCreateTask : //TODO: should be injected readonly PromptService _prompt = new ConsolePromptService(); - public WinServiceCreateTask(string machineName, string serviceName) - : base(machineName, serviceName) + public WinServiceCreateTask(string machineName, string serviceName, string wmiUserName=null, string wmiPassword=null) + : base(machineName, serviceName, wmiUserName, wmiPassword) { } @@ -65,8 +65,12 @@ public override DeploymentResult Execute() if (shouldPromptForPassword()) Password = _prompt.Prompt("Win Service '{0}' For User '{1}' Password".FormatWith(ServiceName, UserName)); - ServiceReturnCode returnCode = WmiService.Create(MachineName, ServiceName, ServiceDisplayName, ServiceLocation, - StartMode, UserName, Password, Dependencies); + string displayName = ServiceDisplayName; + if(string.IsNullOrEmpty(displayName)) + displayName = ServiceName; + + ServiceReturnCode returnCode = WmiService.Create(MachineName, ServiceName, displayName, ServiceLocation, + StartMode, UserName, Password, Dependencies, WmiUserName, WmiPassword); if (returnCode != ServiceReturnCode.Success) result.AddAlert("Create service returned {0}".FormatWith(returnCode.ToString())); diff --git a/product/dropkick/Tasks/WinService/WinServiceDeleteTask.cs b/product/dropkick/Tasks/WinService/WinServiceDeleteTask.cs index 32c34f4f..3cf96ef7 100644 --- a/product/dropkick/Tasks/WinService/WinServiceDeleteTask.cs +++ b/product/dropkick/Tasks/WinService/WinServiceDeleteTask.cs @@ -18,7 +18,7 @@ namespace dropkick.Tasks.WinService public class WinServiceDeleteTask : BaseServiceTask { - public WinServiceDeleteTask(string machineName, string serviceName) : base(machineName, serviceName) + public WinServiceDeleteTask(string machineName, string serviceName, string wmiUserName=null, string wmiPassword=null) : base(machineName, serviceName, wmiUserName, wmiPassword) { } @@ -30,16 +30,29 @@ public override string Name public override DeploymentResult VerifyCanRun() { var result = new DeploymentResult(); - + if(!ServiceExists()) + { + result.AddNote("Cannot delete service '{0}', service does not exist".FormatWith(ServiceName)); + } return result; } public override DeploymentResult Execute() { - var result = new DeploymentResult(); - - ServiceReturnCode returnCode = WmiService.Delete(MachineName, ServiceName); - + var result = new DeploymentResult(); + + if (!ServiceExists()) + { + result.AddNote("Cannot delete service '{0}', service does not exist".FormatWith(ServiceName)); + } + else + { + ServiceReturnCode returnCode = WmiService.Delete(MachineName, ServiceName, WmiUserName, WmiPassword); + if(returnCode != ServiceReturnCode.Success) + { + result.AddAlert("Deleting service '{0}' failed: '{1}'".FormatWith(ServiceName, returnCode)); + } + } return result; } } diff --git a/product/dropkick/Tasks/WinService/WinServiceStartTask.cs b/product/dropkick/Tasks/WinService/WinServiceStartTask.cs index d580e463..ed4e63d5 100644 --- a/product/dropkick/Tasks/WinService/WinServiceStartTask.cs +++ b/product/dropkick/Tasks/WinService/WinServiceStartTask.cs @@ -9,8 +9,8 @@ namespace dropkick.Tasks.WinService public class WinServiceStartTask : BaseServiceTask { - public WinServiceStartTask(string machineName, string serviceName) - : base(machineName, serviceName) + public WinServiceStartTask(string machineName, string serviceName, string wmiUserName=null, string wmiPassword=null) + : base(machineName, serviceName, wmiUserName, wmiPassword) { } @@ -31,7 +31,7 @@ public override DeploymentResult VerifyCanRun() } else { - result.AddAlert(string.Format("Can't find service '{0}'", ServiceName)); + result.AddError(string.Format("Can't find service '{0}'", ServiceName)); } return result; @@ -43,26 +43,68 @@ public override DeploymentResult Execute() if (ServiceExists()) { - using (var c = new ServiceController(ServiceName, MachineName)) + if(string.IsNullOrEmpty(WmiUserName) || string.IsNullOrEmpty(WmiPassword)) { - Logging.Coarse("[svc] Starting service '{0}'", ServiceName); - try + using (var c = new ServiceController(ServiceName, MachineName)) { - c.Start(); - LogCoarseGrain("[svc] Waiting up to 60 seconds because Windows can be silly"); - c.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(60)); + Logging.Coarse("[svc] Starting service '{0}'", ServiceName); + try + { + c.Start(); + LogCoarseGrain("[svc] Waiting up to 60 seconds because Windows can be silly"); + c.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(60)); + } + catch (InvalidOperationException ex) + { + result.AddError("The service '{0}' did not start, most likely due to a logon issue.".FormatWith(ServiceName), ex); + LogCoarseGrain("The service '{0}' did not start, most likely due to a logon issue.{1}{2}", ServiceName, Environment.NewLine, ex); + return result; + } + catch (TimeoutException) + { + result.AddAlert("Service '{0}' did not finish starting during the specified timeframe. You will need to manually verify if the service started successfully.", ServiceName); + LogCoarseGrain("Service '{0}' did not finish starting during the specified timeframe. You will need to manually verify if the service started successfully.", ServiceName); + return result; + } } - catch (InvalidOperationException ex) + } + else + { + Logging.Coarse("[svc] Starting service '{0}'", ServiceName); + if (ServiceIsRunning()) { - result.AddError("The service '{0}' did not start, most likely due to a logon issue.".FormatWith(ServiceName), ex); - LogCoarseGrain("The service '{0}' did not start, most likely due to a logon issue.{1}{2}", ServiceName, Environment.NewLine, ex); - return result; + LogCoarseGrain("[svc] Service '{0}' is already running".FormatWith(ServiceName)); } - catch (TimeoutException) + else { - result.AddAlert("Service '{0}' did not finish starting during the specified timeframe. You will need to manually verify if the service started successfully.", ServiceName); - LogCoarseGrain("Service '{0}' did not finish starting during the specified timeframe. You will need to manually verify if the service started successfully.", ServiceName); - return result; + try + { + var returnCode = dropkick.Wmi.WmiService.Start(MachineName, ServiceName, WmiUserName, WmiPassword); + switch(returnCode) + { + case Wmi.ServiceReturnCode.Success: + if(!ServiceIsRunning()) + { + result.AddError("Failed to start service '{0}', most likely due to a logon issue.".FormatWith(ServiceName)); + LogCoarseGrain("The service '{0}' did not start, most likely due to a logon issue.", ServiceName); + break; + } + else + { + //good! + } + break; + default: + result.AddError("Failed to start service '{0}', most likely due to a logon issue.".FormatWith(ServiceName)); + LogCoarseGrain("The service '{0}' did not start, most likely due to a logon issue.", ServiceName); + break; + } + } + catch(Exception ex) + { + result.AddError("The service '{0}' did not start, most likely due to a logon issue.".FormatWith(ServiceName), ex); + LogCoarseGrain("The service '{0}' did not start, most likely due to a logon issue.{1}{2}", ServiceName, Environment.NewLine, ex); + } } } result.AddGood("Started the service '{0}'", ServiceName); diff --git a/product/dropkick/Tasks/WinService/WinServiceStopTask.cs b/product/dropkick/Tasks/WinService/WinServiceStopTask.cs index c6e43db2..6e1ad33c 100644 --- a/product/dropkick/Tasks/WinService/WinServiceStopTask.cs +++ b/product/dropkick/Tasks/WinService/WinServiceStopTask.cs @@ -23,8 +23,8 @@ namespace dropkick.Tasks.WinService public class WinServiceStopTask : BaseServiceTask { - public WinServiceStopTask(string machineName, string serviceName) - : base(machineName, serviceName) + public WinServiceStopTask(string machineName, string serviceName, string wmiUserName=null, string wmiPassword=null) + : base(machineName, serviceName, wmiUserName, wmiPassword) { } @@ -57,21 +57,49 @@ public override DeploymentResult Execute() if (ServiceExists()) { - using (var c = new ServiceController(ServiceName, MachineName)) + if(string.IsNullOrEmpty(WmiUserName) || string.IsNullOrEmpty(WmiPassword)) { - Logging.Coarse("[svc] Stopping service '{0}'", ServiceName); - if (c.CanStop) + using (var c = new ServiceController(ServiceName, MachineName)) { - int pid = GetProcessId(ServiceName); + Logging.Coarse("[svc] Stopping service '{0}'", ServiceName); + if (c.CanStop) + { + int pid = GetProcessId(ServiceName); - c.Stop(); - c.WaitForStatus(ServiceControllerStatus.Stopped, 30.Seconds()); + c.Stop(); + c.WaitForStatus(ServiceControllerStatus.Stopped, 30.Seconds()); - WaitForProcessToDie(pid); + WaitForProcessToDie(pid); + } } + result.AddGood("Stopped Service '{0}'", ServiceName); + Logging.Coarse("[svc] Stopped service '{0}'", ServiceName); + } + else + { + if(!ServiceIsRunning()) + { + result.AddGood("Stopping Service '{0}', Service Already Stopped", ServiceName); + Logging.Coarse("[svc] Stopping service '{0}', service already stopped", ServiceName); + } + else + { + var status = dropkick.Wmi.WmiService.Stop(MachineName, ServiceName, WmiUserName, WmiPassword); + switch (status) + { + case Wmi.ServiceReturnCode.StatusServiceExists: + case Wmi.ServiceReturnCode.Success: + result.AddGood("Stopped Service '{0}'", ServiceName); + Logging.Coarse("[svc] Stopped service '{0}'", ServiceName); + break; + default: + //BAD + throw new Exception("Failed to stop service {0}: {1}".FormatWith(ServiceName, status)); + } + } + result.AddGood("Stopped Service '{0}'", ServiceName); + Logging.Coarse("[svc] Stopped service '{0}'", ServiceName); } - result.AddGood("Stopped Service '{0}'", ServiceName); - Logging.Coarse("[svc] Stopped service '{0}'", ServiceName); } else { diff --git a/product/dropkick/Wmi/WmiHelper.cs b/product/dropkick/Wmi/WmiHelper.cs index 578a0dad..c4213dd0 100644 --- a/product/dropkick/Wmi/WmiHelper.cs +++ b/product/dropkick/Wmi/WmiHelper.cs @@ -5,14 +5,16 @@ namespace dropkick.Wmi public class WmiHelper { - public static ManagementScope Connect(string machineName) + public static ManagementScope Connect(string machineName, string userName=null, string password=null) { var scope = new ManagementScope(@"\\{0}\root\cimv2".FormatWith(machineName)) { Options = { Impersonation = ImpersonationLevel.Impersonate, - EnablePrivileges = true + EnablePrivileges = true, + Username = userName, + Password = password } }; @@ -28,18 +30,18 @@ public static ManagementScope Connect(string machineName) return scope; } - static ManagementObject GetInstanceByName(string machineName, string className, string name) { + static ManagementObject GetInstanceByName(string machineName, string className, string name, string userName=null, string password=null) { var query = "SELECT * FROM " + className + " WHERE Name = '" + name + "'"; - foreach (ManagementObject manObject in Query(machineName,query)) { + foreach (ManagementObject manObject in Query(machineName,query, userName, password)) { return manObject; } return null; } - public static ManagementObjectCollection Query(string machineName, string query) + public static ManagementObjectCollection Query(string machineName, string query, string userName=null, string password=null) { - ManagementScope scope = Connect(machineName); + ManagementScope scope = Connect(machineName, userName, password); var queryObj = new ObjectQuery(query); var searcher = new ManagementObjectSearcher(scope, queryObj); ManagementObjectCollection results = searcher.Get(); @@ -49,9 +51,9 @@ public static ManagementObjectCollection Query(string machineName, string query) - static ManagementClass GetStaticByName(string machineName, string className) + static ManagementClass GetStaticByName(string machineName, string className, string userName=null, string password=null) { - ManagementScope scope = Connect(machineName); + ManagementScope scope = Connect(machineName, userName, password); var getOptions = new ObjectGetOptions(); var path = new ManagementPath(className); var manClass = new ManagementClass(scope, path, getOptions); @@ -64,6 +66,11 @@ public static int InvokeInstanceMethod(string machineName, string className, str return InvokeInstanceMethod(machineName, className, name, methodName, null); } + public static int InvokeInstanceMethodWithAuthentication(string machineName, string className, string name, string methodName, string userName, string password) + { + return InvokeInstanceMethodWithAuthentication(machineName, className, name, methodName, userName, password, null); + } + public static int InvokeInstanceMethod(string machineName, string className, string name, string methodName, object[] parameters) { @@ -79,6 +86,21 @@ public static int InvokeInstanceMethod(string machineName, string className, str } } + public static int InvokeInstanceMethodWithAuthentication(string machineName, string className, string name, string methodName, + string userName, string password, object[] parameters) + { + try + { + ManagementObject manObject = GetInstanceByName(machineName, className, name, userName, password); + object result = manObject.InvokeMethod(methodName, parameters); + return Convert.ToInt32(result); + } + catch + { + return -1; + } + } + public static int InvokeStaticMethod(string machineName, string className, string methodName) { return InvokeStaticMethod(machineName, className, methodName, null); @@ -100,5 +122,22 @@ public static int InvokeStaticMethod(string machineName, string className, strin return -1; } } + + public static int InvokeStaticMethodWithAuthentication(string machineName, string className, string methodName, + object[] parameters, string wmiUserName, string wmiPassword) + { + try + { + using (var managementClass = GetStaticByName(machineName, className, wmiUserName, wmiPassword)) + { + object result = managementClass.InvokeMethod(methodName, parameters); + return Convert.ToInt32(result); + } + } + catch + { + return -1; + } + } } } \ No newline at end of file diff --git a/product/dropkick/Wmi/WmiService.cs b/product/dropkick/Wmi/WmiService.cs index be8eb212..8949b557 100644 --- a/product/dropkick/Wmi/WmiService.cs +++ b/product/dropkick/Wmi/WmiService.cs @@ -12,7 +12,7 @@ public class WmiService public static ServiceReturnCode Create(string machineName, string serviceName, string serviceDisplayName, string serviceLocation, ServiceStartMode startMode, string userName, - string password, string[] dependencies) + string password, string[] dependencies, string wmiUserName=null, string wmiPassword=null) { if (userName != null && userName.IndexOf('\\') < 0) { @@ -39,7 +39,7 @@ public static ServiceReturnCode Create(string machineName, string serviceName, s null, // LoadOrderGroupDependencies | Load Order Dependencies dependencies // ServiceDependencies }; - return (ServiceReturnCode) WmiHelper.InvokeStaticMethod(machineName, CLASSNAME, methodName, parameters); + return (ServiceReturnCode) WmiHelper.InvokeStaticMethodWithAuthentication(machineName, CLASSNAME, methodName, parameters, wmiUserName, wmiPassword); } catch { @@ -47,13 +47,13 @@ public static ServiceReturnCode Create(string machineName, string serviceName, s } } - public static ServiceReturnCode Delete(string machineName, string serviceName) + public static ServiceReturnCode Delete(string machineName, string serviceName, string wmiUserName=null, string wmiPassword=null) { try { string methodName = "Delete"; return - (ServiceReturnCode) WmiHelper.InvokeInstanceMethod(machineName, CLASSNAME, serviceName, methodName); + (ServiceReturnCode) WmiHelper.InvokeInstanceMethodWithAuthentication(machineName, CLASSNAME, serviceName, methodName, wmiUserName, wmiPassword); } catch { @@ -61,13 +61,13 @@ public static ServiceReturnCode Delete(string machineName, string serviceName) } } - public static ServiceReturnCode Start(string machineName, string serviceName) + public static ServiceReturnCode Start(string machineName, string serviceName, string wmiUserName, string wmiPassword) { try { string methodName = "StartService"; return - (ServiceReturnCode) WmiHelper.InvokeInstanceMethod(machineName, CLASSNAME, serviceName, methodName); + (ServiceReturnCode) WmiHelper.InvokeInstanceMethodWithAuthentication(machineName, CLASSNAME, serviceName, methodName, wmiUserName, wmiPassword); } catch { @@ -75,13 +75,13 @@ public static ServiceReturnCode Start(string machineName, string serviceName) } } - public static ServiceReturnCode Stop(string machineName, string serviceName) + public static ServiceReturnCode Stop(string machineName, string serviceName, string wmiUserName, string wmiPassword) { try { string methodName = "StopService"; return - (ServiceReturnCode) WmiHelper.InvokeInstanceMethod(machineName, CLASSNAME, serviceName, methodName); + (ServiceReturnCode) WmiHelper.InvokeInstanceMethodWithAuthentication(machineName, CLASSNAME, serviceName, methodName, wmiUserName, wmiPassword); } catch { @@ -103,13 +103,13 @@ public static ServiceReturnCode Pause(string machineName, string serviceName) } } - public static ServiceReturnCode QueryService(string machineName, string serviceName) + public static ServiceReturnCode QueryService(string machineName, string serviceName, string userName, string password) { try { string methodName = "InterrogateService"; return - (ServiceReturnCode) WmiHelper.InvokeInstanceMethod(machineName, CLASSNAME, serviceName, methodName); + (ServiceReturnCode) WmiHelper.InvokeInstanceMethodWithAuthentication(machineName, CLASSNAME, serviceName, methodName, userName, password); } catch { From a83ce9c693090220186882ad77e18a8633e62d7e Mon Sep 17 00:00:00 2001 From: Mike Mooney Date: Mon, 4 Nov 2013 15:41:09 -0500 Subject: [PATCH 2/5] Fixes for remote user authentication --- .../WinService/ProtoWinServiceCreateTask.cs | 19 ++++++++++--------- .../WinService/ProtoWinServiceDeleteTask.cs | 10 ++++++++-- .../WinService/ProtoWinServiceStartTask.cs | 10 ++++++++-- .../Dsl/WinService/ProtoWinServiceStopTask.cs | 10 ++++++++-- .../Dsl/WinService/ProtoWinServiceTask.cs | 2 +- product/dropkick/FileSystem/DotNetPath.cs | 9 +++++++-- product/dropkick/FileSystem/Path.cs | 1 + product/dropkick/Wmi/Win32Share.cs | 4 ++-- 8 files changed, 45 insertions(+), 20 deletions(-) diff --git a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceCreateTask.cs b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceCreateTask.cs index 9f15791b..5c033a25 100644 --- a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceCreateTask.cs +++ b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceCreateTask.cs @@ -36,10 +36,18 @@ public class ProtoWinServiceCreateTask : string _wmiUserName; string _wmiPassword; - public ProtoWinServiceCreateTask(Path path, string serviceName) + public ProtoWinServiceCreateTask(Path path, string serviceName, string wmiUserName, string wmiPassword) { _path = path; _serviceName = ReplaceTokens(serviceName); + if(!string.IsNullOrEmpty(wmiUserName)) + { + _wmiUserName = ReplaceTokens(wmiUserName); + } + if(!string.IsNullOrEmpty(wmiPassword)) + { + _wmiPassword = ReplaceTokens(wmiPassword); + } } public WinServiceCreateOptions WithDisplayName(string displayName) @@ -60,13 +68,6 @@ public WinServiceCreateOptions WithStartMode(ServiceStartMode mode) return this; } - public WinServiceCreateOptions WithAuthentication(string userName, string password) - { - _wmiUserName = userName; - _wmiPassword = password; - return this; - } - public WinServiceCreateOptions WithCredentials(string username, string password) { _userName = ReplaceTokens(username); @@ -85,7 +86,7 @@ public WinServiceCreateOptions AddDependency(string name) public override void RegisterRealTasks(PhysicalServer site) { string serviceLocation = _installPath; - serviceLocation = _path.GetPhysicalPath(site, _installPath, true); + serviceLocation = _path.GetPhysicalPath(site, _installPath, true, _wmiUserName, _wmiPassword); site.AddTask(new WinServiceCreateTask(site.Name, _serviceName, _wmiUserName, _wmiPassword) { diff --git a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceDeleteTask.cs b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceDeleteTask.cs index a83651e3..88b0106b 100644 --- a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceDeleteTask.cs +++ b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceDeleteTask.cs @@ -26,8 +26,14 @@ public class ProtoWinServiceDeleteTask : public ProtoWinServiceDeleteTask(string serviceName, string wmiUserName=null, string wmiPassword=null) { _serviceName = ReplaceTokens(serviceName); - _wmiUserName = ReplaceTokens(wmiUserName); - _wmiPassword = ReplaceTokens(wmiPassword); + if(!string.IsNullOrEmpty(wmiUserName)) + { + _wmiUserName = ReplaceTokens(wmiUserName); + } + if(!string.IsNullOrEmpty(wmiPassword)) + { + _wmiPassword = ReplaceTokens(wmiPassword); + } } public override void RegisterRealTasks(PhysicalServer site) diff --git a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStartTask.cs b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStartTask.cs index 27b5e107..e230fa99 100644 --- a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStartTask.cs +++ b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStartTask.cs @@ -26,8 +26,14 @@ public class ProtoWinServiceStartTask : public ProtoWinServiceStartTask(string serviceName, string wmiUserName=null, string wmiPassword=null) { _serviceName = ReplaceTokens(serviceName); - _wmiUserName = ReplaceTokens(wmiUserName); - _wmiPassword = ReplaceTokens(wmiPassword); + if (!string.IsNullOrEmpty(wmiUserName)) + { + _wmiUserName = ReplaceTokens(wmiUserName); + } + if (!string.IsNullOrEmpty(wmiPassword)) + { + _wmiPassword = ReplaceTokens(wmiPassword); + } } public override void RegisterRealTasks(PhysicalServer s) diff --git a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStopTask.cs b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStopTask.cs index f90748f8..05f52f70 100644 --- a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStopTask.cs +++ b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStopTask.cs @@ -26,8 +26,14 @@ public class ProtoWinServiceStopTask : public ProtoWinServiceStopTask(string serviceName, string wmiUserName=null, string wmiPassword=null) { _serviceName = ReplaceTokens(serviceName); - _wmiUserName = ReplaceTokens(wmiUserName); - _wmiPassword = ReplaceTokens(wmiPassword); + if (!string.IsNullOrEmpty(wmiUserName)) + { + _wmiUserName = ReplaceTokens(wmiUserName); + } + if (!string.IsNullOrEmpty(wmiPassword)) + { + _wmiPassword = ReplaceTokens(wmiPassword); + } } public override void RegisterRealTasks(PhysicalServer s) diff --git a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceTask.cs b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceTask.cs index de44cf11..b4c7e7d4 100644 --- a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceTask.cs +++ b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceTask.cs @@ -61,7 +61,7 @@ public void Stop() public WinServiceCreateOptions Create() { - var proto = new ProtoWinServiceCreateTask(new DotNetPath(), _serviceName); + var proto = new ProtoWinServiceCreateTask(new DotNetPath(), _serviceName, _wmiUserName, _wmiPassword); _protoServer.RegisterProtoTask(proto); return proto; } diff --git a/product/dropkick/FileSystem/DotNetPath.cs b/product/dropkick/FileSystem/DotNetPath.cs index 3b017316..60cc87df 100644 --- a/product/dropkick/FileSystem/DotNetPath.cs +++ b/product/dropkick/FileSystem/DotNetPath.cs @@ -25,7 +25,12 @@ public class DotNetPath : Path { #region Path Members - public string GetPhysicalPath(PhysicalServer site, string path,bool forceLocalPath) + public string GetPhysicalPath(PhysicalServer site, string path, bool forceLocalPath) + { + return this.GetPhysicalPath(site, path, forceLocalPath, null, null); + } + + public string GetPhysicalPath(PhysicalServer site, string path,bool forceLocalPath, string wmiUserName, string wmiPassword) { var standardizedPath = path; if (!IsUncPath(standardizedPath)) @@ -45,7 +50,7 @@ public string GetPhysicalPath(PhysicalServer site, string path,bool forceLocalPa if (shareMatch.Success) { var shareName = shareMatch.Groups["shareName"].Value; - serviceLocation = Win32Share.GetLocalPathForShare(site.Name, shareName); + serviceLocation = Win32Share.GetLocalPathForShare(site.Name, shareName, wmiUserName, wmiPassword); } var rest = shareMatch.Groups["rest"].Value; standardizedPath = System.IO.Path.Combine(serviceLocation, rest); diff --git a/product/dropkick/FileSystem/Path.cs b/product/dropkick/FileSystem/Path.cs index 28e9d2e9..c02946a6 100644 --- a/product/dropkick/FileSystem/Path.cs +++ b/product/dropkick/FileSystem/Path.cs @@ -18,6 +18,7 @@ namespace dropkick.FileSystem public interface Path { string GetPhysicalPath(PhysicalServer server, string path, bool forceLocalPath); + string GetPhysicalPath(PhysicalServer server, string path, bool forceLocalPath, string wmiUserName, string wmiPassword); string Combine(string root, params string[] ex); string GetFullPath(string path); bool IsFile(string path); diff --git a/product/dropkick/Wmi/Win32Share.cs b/product/dropkick/Wmi/Win32Share.cs index 96857d7b..d26b8b05 100644 --- a/product/dropkick/Wmi/Win32Share.cs +++ b/product/dropkick/Wmi/Win32Share.cs @@ -73,10 +73,10 @@ public static ShareReturnCode Delete(string serverName, string shareName) return ShareReturnCode.UnknownFailure; } - public static string GetLocalPathForShare(string serverName, string shareName) + public static string GetLocalPathForShare(string serverName, string shareName, string wmiUserName=null, string wmiPassword=null) { var query = new WqlObjectQuery("select Name, Path from Win32_Share"); - var scope = WmiHelper.Connect(serverName); + var scope = WmiHelper.Connect(serverName, wmiUserName, wmiPassword); using (var search = new ManagementObjectSearcher(scope, query)) { From 4b7b62fe521f1259e1dde0e45c10a8ea2e318062 Mon Sep 17 00:00:00 2001 From: Mike Mooney Date: Mon, 4 Nov 2013 15:50:35 -0500 Subject: [PATCH 3/5] Added task for authenticating share --- .../Configuration/Dsl/Files/Extension.cs | 6 + .../OpenFolderShareAuthenticationProtoTask.cs | 31 +++ .../FileSystem/FileShareAuthenticator.cs | 49 +++++ .../FileSystem/PinvokeWindowsNetworking.cs | 178 ++++++++++++++++++ .../OpenFolderShareAuthenticationTask.cs | 81 ++++++++ product/dropkick/dropkick.csproj | 4 + 6 files changed, 349 insertions(+) create mode 100644 product/dropkick/Configuration/Dsl/Files/OpenFolderShareAuthenticationProtoTask.cs create mode 100644 product/dropkick/FileSystem/FileShareAuthenticator.cs create mode 100644 product/dropkick/FileSystem/PinvokeWindowsNetworking.cs create mode 100644 product/dropkick/Tasks/Files/OpenFolderShareAuthenticationTask.cs diff --git a/product/dropkick/Configuration/Dsl/Files/Extension.cs b/product/dropkick/Configuration/Dsl/Files/Extension.cs index 92d94c86..1d9aba9a 100644 --- a/product/dropkick/Configuration/Dsl/Files/Extension.cs +++ b/product/dropkick/Configuration/Dsl/Files/Extension.cs @@ -98,5 +98,11 @@ public static ExistsOptions Exists(this ProtoServer protoserver, string reason, protoserver.RegisterProtoTask(proto); return proto; } + + public static void OpenFolderShareWithAuthentication(this ProtoServer protoServer, string folderName, string userName, string password) + { + var task = new OpenFolderShareAuthenticationProtoTask(folderName, userName, password); + protoServer.RegisterProtoTask(task); + } } } \ No newline at end of file diff --git a/product/dropkick/Configuration/Dsl/Files/OpenFolderShareAuthenticationProtoTask.cs b/product/dropkick/Configuration/Dsl/Files/OpenFolderShareAuthenticationProtoTask.cs new file mode 100644 index 00000000..0db88863 --- /dev/null +++ b/product/dropkick/Configuration/Dsl/Files/OpenFolderShareAuthenticationProtoTask.cs @@ -0,0 +1,31 @@ +using dropkick.Tasks; +using dropkick.Tasks.Files; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace dropkick.Configuration.Dsl.Files +{ + public class OpenFolderShareAuthenticationProtoTask : BaseProtoTask + { + private readonly string _folderName; + private readonly string _userName; + private readonly string _password; + + public OpenFolderShareAuthenticationProtoTask(string folderName, string userName, string password) + { + _folderName = ReplaceTokens(folderName); + _userName = userName; + _password = password; + } + + public override void RegisterRealTasks(dropkick.DeploymentModel.PhysicalServer server) + { + string to = server.MapPath(_folderName); + + var task = new OpenFolderShareAuthenticationTask(to, _userName, _password); + server.AddTask(task); + } + } +} diff --git a/product/dropkick/FileSystem/FileShareAuthenticator.cs b/product/dropkick/FileSystem/FileShareAuthenticator.cs new file mode 100644 index 00000000..c28fa0f9 --- /dev/null +++ b/product/dropkick/FileSystem/FileShareAuthenticator.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace dropkick.FileSystem +{ + public static class FileShareAuthenticator + { + public static FileShareAuthenticationContext BeginFileShareAuthentication(string remoteUnc, string userName, string password) + { + string error = PinvokeWindowsNetworking.connectToRemote(remoteUnc, userName, password); + if (!string.IsNullOrEmpty(error)) + { + throw new Exception("Error calling PinvokeWindowsNetworking.connectToRemote: " + error); + } + return new FileShareAuthenticationContext(remoteUnc, userName, password); + } + + public class FileShareAuthenticationContext : IDisposable + { + private readonly string _remoteUnc; + private readonly string _userName; + private readonly string _password; + private bool _active; + + public FileShareAuthenticationContext(string remoteUnc, string userName, string password) + { + _remoteUnc = remoteUnc; + _userName = userName; + _password = password; + _active = true; + } + + public void Dispose() + { + if (_active) + { + var error = PinvokeWindowsNetworking.disconnectRemote(_remoteUnc); + if (!string.IsNullOrEmpty(error)) + { + throw new Exception("PinvokeWindowsNetworking.disconnectRemote failed: " + error); + } + _active = false; + } + } + } + } +} diff --git a/product/dropkick/FileSystem/PinvokeWindowsNetworking.cs b/product/dropkick/FileSystem/PinvokeWindowsNetworking.cs new file mode 100644 index 00000000..db868893 --- /dev/null +++ b/product/dropkick/FileSystem/PinvokeWindowsNetworking.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace dropkick.FileSystem +{ + //http://www.dimitrioskouzisloukas.com/blog/index.php?blog=2&title=c_windows_networking_library&more=1&c=1&tb=1&pb=1 + //http://lookfwd.doitforme.gr/blog/media/PinvokeWindowsNetworking.cs + public class PinvokeWindowsNetworking + { + #region Consts + const int RESOURCE_CONNECTED = 0x00000001; + const int RESOURCE_GLOBALNET = 0x00000002; + const int RESOURCE_REMEMBERED = 0x00000003; + + const int RESOURCETYPE_ANY = 0x00000000; + const int RESOURCETYPE_DISK = 0x00000001; + const int RESOURCETYPE_PRINT = 0x00000002; + + const int RESOURCEDISPLAYTYPE_GENERIC = 0x00000000; + const int RESOURCEDISPLAYTYPE_DOMAIN = 0x00000001; + const int RESOURCEDISPLAYTYPE_SERVER = 0x00000002; + const int RESOURCEDISPLAYTYPE_SHARE = 0x00000003; + const int RESOURCEDISPLAYTYPE_FILE = 0x00000004; + const int RESOURCEDISPLAYTYPE_GROUP = 0x00000005; + + const int RESOURCEUSAGE_CONNECTABLE = 0x00000001; + const int RESOURCEUSAGE_CONTAINER = 0x00000002; + + + const int CONNECT_INTERACTIVE = 0x00000008; + const int CONNECT_PROMPT = 0x00000010; + const int CONNECT_REDIRECT = 0x00000080; + const int CONNECT_UPDATE_PROFILE = 0x00000001; + const int CONNECT_COMMANDLINE = 0x00000800; + const int CONNECT_CMD_SAVECRED = 0x00001000; + + const int CONNECT_LOCALDRIVE = 0x00000100; + #endregion + + #region Errors + const int NO_ERROR = 0; + + const int ERROR_ACCESS_DENIED = 5; + const int ERROR_ALREADY_ASSIGNED = 85; + const int ERROR_BAD_DEVICE = 1200; + const int ERROR_BAD_NET_NAME = 67; + const int ERROR_BAD_PROVIDER = 1204; + const int ERROR_CANCELLED = 1223; + const int ERROR_EXTENDED_ERROR = 1208; + const int ERROR_INVALID_ADDRESS = 487; + const int ERROR_INVALID_PARAMETER = 87; + const int ERROR_INVALID_PASSWORD = 1216; + const int ERROR_MORE_DATA = 234; + const int ERROR_NO_MORE_ITEMS = 259; + const int ERROR_NO_NET_OR_BAD_PATH = 1203; + const int ERROR_NO_NETWORK = 1222; + + const int ERROR_BAD_PROFILE = 1206; + const int ERROR_CANNOT_OPEN_PROFILE = 1205; + const int ERROR_DEVICE_IN_USE = 2404; + const int ERROR_NOT_CONNECTED = 2250; + const int ERROR_OPEN_FILES = 2401; + + private struct ErrorClass + { + public int num; + public string message; + public ErrorClass(int num, string message) + { + this.num = num; + this.message = message; + } + } + + + // Created with excel formula: + // ="new ErrorClass("&A1&", """&PROPER(SUBSTITUTE(MID(A1,7,LEN(A1)-6), "_", " "))&"""), " + private static ErrorClass[] ERROR_LIST = new ErrorClass[] { + new ErrorClass(ERROR_ACCESS_DENIED, "Error: Access Denied"), + new ErrorClass(ERROR_ALREADY_ASSIGNED, "Error: Already Assigned"), + new ErrorClass(ERROR_BAD_DEVICE, "Error: Bad Device"), + new ErrorClass(ERROR_BAD_NET_NAME, "Error: Bad Net Name"), + new ErrorClass(ERROR_BAD_PROVIDER, "Error: Bad Provider"), + new ErrorClass(ERROR_CANCELLED, "Error: Cancelled"), + new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"), + new ErrorClass(ERROR_INVALID_ADDRESS, "Error: Invalid Address"), + new ErrorClass(ERROR_INVALID_PARAMETER, "Error: Invalid Parameter"), + new ErrorClass(ERROR_INVALID_PASSWORD, "Error: Invalid Password"), + new ErrorClass(ERROR_MORE_DATA, "Error: More Data"), + new ErrorClass(ERROR_NO_MORE_ITEMS, "Error: No More Items"), + new ErrorClass(ERROR_NO_NET_OR_BAD_PATH, "Error: No Net Or Bad Path"), + new ErrorClass(ERROR_NO_NETWORK, "Error: No Network"), + new ErrorClass(ERROR_BAD_PROFILE, "Error: Bad Profile"), + new ErrorClass(ERROR_CANNOT_OPEN_PROFILE, "Error: Cannot Open Profile"), + new ErrorClass(ERROR_DEVICE_IN_USE, "Error: Device In Use"), + new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"), + new ErrorClass(ERROR_NOT_CONNECTED, "Error: Not Connected"), + new ErrorClass(ERROR_OPEN_FILES, "Error: Open Files"), + }; + + private static string getErrorForNumber(int errNum) + { + foreach (ErrorClass er in ERROR_LIST) + { + if (er.num == errNum) return er.message; + } + return new Win32Exception(errNum).Message; + //return "Error: Unknown, " + errNum; + } + #endregion + + [DllImport("Mpr.dll")] + private static extern int WNetUseConnection( + IntPtr hwndOwner, + NETRESOURCE lpNetResource, + string lpPassword, + string lpUserID, + int dwFlags, + string lpAccessName, + string lpBufferSize, + string lpResult + ); + + [DllImport("Mpr.dll")] + private static extern int WNetCancelConnection2( + string lpName, + int dwFlags, + int fForce + ); + + [StructLayout(LayoutKind.Sequential)] + private class NETRESOURCE + { + public int dwScope = 0; + public int dwType = 0; + public int dwDisplayType = 0; + public int dwUsage = 0; + public string lpLocalName = ""; + public string lpRemoteName = ""; + public string lpComment = ""; + public string lpProvider = ""; + } + + + public static string connectToRemote(string remoteUNC, string username, string password) + { + return connectToRemote(remoteUNC, username, password, false); + } + + public static string connectToRemote(string remoteUNC, string username, string password, bool promptUser) + { + NETRESOURCE nr = new NETRESOURCE(); + nr.dwType = RESOURCETYPE_DISK; + nr.lpRemoteName = remoteUNC; + // nr.lpLocalName = "F:"; + + int ret; + if (promptUser) + ret = WNetUseConnection(IntPtr.Zero, nr, "", "", CONNECT_INTERACTIVE | CONNECT_PROMPT, null, null, null); + else + ret = WNetUseConnection(IntPtr.Zero, nr, password, username, 0, null, null, null); + + if (ret == NO_ERROR) return null; + return getErrorForNumber(ret); + } + + public static string disconnectRemote(string remoteUNC) + { + int ret = WNetCancelConnection2(remoteUNC, CONNECT_UPDATE_PROFILE, 1); + if (ret == NO_ERROR) return null; + return getErrorForNumber(ret); + } + } +} diff --git a/product/dropkick/Tasks/Files/OpenFolderShareAuthenticationTask.cs b/product/dropkick/Tasks/Files/OpenFolderShareAuthenticationTask.cs new file mode 100644 index 00000000..f96978ba --- /dev/null +++ b/product/dropkick/Tasks/Files/OpenFolderShareAuthenticationTask.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using dropkick; +using dropkick.DeploymentModel; +using dropkick.FileSystem; +using System.Text.RegularExpressions; + +namespace dropkick.Tasks.Files +{ + public class OpenFolderShareAuthenticationTask : Task + { + private readonly string _to; + private readonly string _userName; + private readonly string _password; + + public OpenFolderShareAuthenticationTask(string to, string userName, string password) + { + _to = to; + _userName = userName; + _password = password; + } + + public string Name + { + get { return "Creating new empty folder '{0}' with user name '{1}'".FormatWith(_to, _userName); } + } + + public DeploymentResult VerifyCanRun() + { + var result = new DeploymentResult(); + var to = new DotNetPath().GetFullPath(_to); + string toParent = GetRootShare(to); + try + { + using (var context = FileShareAuthenticator.BeginFileShareAuthentication(toParent, _userName, _password)) + { + result.AddGood(System.IO.Directory.Exists(to) ? "'{0}' already exists.".FormatWith(to) : Name); + } + } + catch (Exception err) + { + result.AddError("Failed to access '{0}' as user '{1}'".FormatWith(toParent, _userName), err); + } + //TODO figure out a good verify step... + return result; + } + + private string GetRootShare(string to) + { + var regex = new Regex(@"\\\\[^\\]*\\[^\\]*"); + var match = regex.Match(to); + if (!match.Success) + { + throw new Exception("Unable to parse root share from " + to); + } + return match.Value; + } + + public DeploymentResult Execute() + { + var result = new DeploymentResult(); + var to = new DotNetPath().GetFullPath(_to); + + var toParent = GetRootShare(to); + try + { + using (var context = FileShareAuthenticator.BeginFileShareAuthentication(toParent, _userName, _password)) + { + result.AddGood("'{0}' authenticated with {1}.".FormatWith(to, _userName)); + } + } + catch (Exception err) + { + result.AddError("Failed to access '{0}' as user '{1}'".FormatWith(toParent, _userName), err); + } + return result; + } + } +} diff --git a/product/dropkick/dropkick.csproj b/product/dropkick/dropkick.csproj index e3305793..dc01c0dc 100644 --- a/product/dropkick/dropkick.csproj +++ b/product/dropkick/dropkick.csproj @@ -94,6 +94,7 @@ + @@ -139,6 +140,7 @@ + @@ -162,6 +164,7 @@ + @@ -350,6 +353,7 @@ + From 8f2da7169b66341015edac2bb04830a0f61e4bc6 Mon Sep 17 00:00:00 2001 From: Mike Mooney Date: Tue, 27 May 2014 20:04:06 -0400 Subject: [PATCH 4/5] Improved error message --- product/dropkick/Wmi/WmiHelper.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/product/dropkick/Wmi/WmiHelper.cs b/product/dropkick/Wmi/WmiHelper.cs index c4213dd0..b12b9d9c 100644 --- a/product/dropkick/Wmi/WmiHelper.cs +++ b/product/dropkick/Wmi/WmiHelper.cs @@ -24,7 +24,14 @@ public static ManagementScope Connect(string machineName, string userName=null, } catch (Exception exc) { - throw new SystemException("Problem connecting WMI scope on " + machineName + ".", exc); + if(string.IsNullOrEmpty(userName)) + { + throw new SystemException("Problem connecting WMI scope on " + machineName + " with current user account.", exc); + } + else + { + throw new SystemException("Problem connecting WMI scope on " + machineName + " with user account " + userName, exc); + } } return scope; From 26b1c2e0ec3a29ecb253cc2bdcfb5e88f07ac128 Mon Sep 17 00:00:00 2001 From: Mike Mooney Date: Wed, 28 May 2014 08:48:10 -0400 Subject: [PATCH 5/5] Changed to use WMI auth info as ambient values, instead of passing it around everywhere --- .../WinService/WinTestsWithAuthentication.cs | 23 +++--- .../Dsl/Authentication/Extension.cs | 21 ++++++ .../WinService/ProtoWinServiceCreateTask.cs | 16 +---- .../WinService/ProtoWinServiceDeleteTask.cs | 14 +--- .../WinService/ProtoWinServiceStartTask.cs | 14 +--- .../Dsl/WinService/ProtoWinServiceStopTask.cs | 14 +--- .../Dsl/WinService/ProtoWinServiceTask.cs | 21 ++---- .../Dsl/WinService/WinServiceOptions.cs | 1 - product/dropkick/FileSystem/DotNetPath.cs | 7 +- product/dropkick/FileSystem/Path.cs | 1 - .../Tasks/WinService/BaseServiceTask.cs | 14 ++-- .../Tasks/WinService/WinServiceCreateTask.cs | 6 +- .../Tasks/WinService/WinServiceDeleteTask.cs | 4 +- .../Tasks/WinService/WinServiceStartTask.cs | 10 +-- .../Tasks/WinService/WinServiceStopTask.cs | 8 +-- product/dropkick/Wmi/Win32Share.cs | 4 +- product/dropkick/Wmi/WmiHelper.cs | 72 +++++++------------ product/dropkick/Wmi/WmiService.cs | 34 +++++---- product/dropkick/dropkick.csproj | 1 + 19 files changed, 121 insertions(+), 164 deletions(-) create mode 100644 product/dropkick/Configuration/Dsl/Authentication/Extension.cs diff --git a/product/dropkick.tests/Tasks/WinService/WinTestsWithAuthentication.cs b/product/dropkick.tests/Tasks/WinService/WinTestsWithAuthentication.cs index 087c4502..c6a6e82a 100644 --- a/product/dropkick.tests/Tasks/WinService/WinTestsWithAuthentication.cs +++ b/product/dropkick.tests/Tasks/WinService/WinTestsWithAuthentication.cs @@ -36,7 +36,7 @@ private WmiAuthenticationInfo GetAuthenticationInfo() { return (WmiAuthenticationInfo)serializer.Deserialize(reader); } - } + } [Test] [Explicit] @@ -45,16 +45,18 @@ public void Start() { var authInfo = GetAuthenticationInfo(); - var t = new WinServiceStopTask(authInfo.MachineName, "IISADMIN", authInfo.WmiUserName, authInfo.WmiPassword); + WmiService.WithAuthentication(authInfo.WmiUserName, authInfo.WmiPassword); + + var t = new WinServiceStopTask(authInfo.MachineName, "IISADMIN"); var verifyStopResult = t.VerifyCanRun(); Log(verifyStopResult); AssertSuccess(verifyStopResult); - + var stopResult = t.Execute(); Log(stopResult); AssertSuccess(stopResult); - var t2 = new WinServiceStartTask(authInfo.MachineName, "IISADMIN", authInfo.WmiUserName, authInfo.WmiPassword); + var t2 = new WinServiceStartTask(authInfo.MachineName, "IISADMIN"); var verifyStartResult = t2.VerifyCanRun(); Log(verifyStartResult); AssertSuccess(verifyStartResult); @@ -70,7 +72,8 @@ public void RemoteCreate() { var authInfo = GetAuthenticationInfo(); - var t = new WinServiceCreateTask(authInfo.MachineName, "DropKicKTestService", authInfo.WmiUserName, authInfo.WmiPassword); + WmiService.WithAuthentication(authInfo.WmiUserName, authInfo.WmiPassword); + var t = new WinServiceCreateTask(authInfo.MachineName, "DropKicKTestService"); t.ServiceLocation = "C:\\Test\\TestService.exe"; t.StartMode = ServiceStartMode.Automatic; @@ -91,7 +94,9 @@ public void RemoteDelete() { var authInfo = GetAuthenticationInfo(); - var t = new WinServiceDeleteTask(authInfo.MachineName, "DropkicKTestService", authInfo.ServiceUserName, authInfo.ServicePassword); + WmiService.WithAuthentication(authInfo.ServiceUserName, authInfo.ServicePassword); + + var t = new WinServiceDeleteTask(authInfo.MachineName, "DropkicKTestService"); DeploymentResult o = t.VerifyCanRun(); Log(o); @@ -108,14 +113,14 @@ private void AssertSuccess(DeploymentResult result) private void Log(DeploymentResult result) { - if(result != null) + if (result != null) { - foreach(var item in result) + foreach (var item in result) { Debug.WriteLine(item.Message); } } - } + } } } diff --git a/product/dropkick/Configuration/Dsl/Authentication/Extension.cs b/product/dropkick/Configuration/Dsl/Authentication/Extension.cs new file mode 100644 index 00000000..e60e86a5 --- /dev/null +++ b/product/dropkick/Configuration/Dsl/Authentication/Extension.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using dropkick.Wmi; +using dropkick.StringInterpolation; + +namespace dropkick.Configuration.Dsl.Authentication +{ + public static class Extension + { + public static ProtoServer WithAuthentication(this ProtoServer server, string remoteUserName, string remotePassword) + { + var interpolator = new CaseInsensitiveInterpolator(); + remoteUserName = interpolator.ReplaceTokens(HUB.Settings, remoteUserName); + remotePassword = interpolator.ReplaceTokens(HUB.Settings, remotePassword); + WmiService.WithAuthentication(remoteUserName, remotePassword); + return server; + } + } +} diff --git a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceCreateTask.cs b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceCreateTask.cs index 5c033a25..5add6935 100644 --- a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceCreateTask.cs +++ b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceCreateTask.cs @@ -33,21 +33,11 @@ public class ProtoWinServiceCreateTask : ServiceStartMode _startMode; string _userName; Path _path; - string _wmiUserName; - string _wmiPassword; - public ProtoWinServiceCreateTask(Path path, string serviceName, string wmiUserName, string wmiPassword) + public ProtoWinServiceCreateTask(Path path, string serviceName) { _path = path; _serviceName = ReplaceTokens(serviceName); - if(!string.IsNullOrEmpty(wmiUserName)) - { - _wmiUserName = ReplaceTokens(wmiUserName); - } - if(!string.IsNullOrEmpty(wmiPassword)) - { - _wmiPassword = ReplaceTokens(wmiPassword); - } } public WinServiceCreateOptions WithDisplayName(string displayName) @@ -86,9 +76,9 @@ public WinServiceCreateOptions AddDependency(string name) public override void RegisterRealTasks(PhysicalServer site) { string serviceLocation = _installPath; - serviceLocation = _path.GetPhysicalPath(site, _installPath, true, _wmiUserName, _wmiPassword); + serviceLocation = _path.GetPhysicalPath(site, _installPath, true); - site.AddTask(new WinServiceCreateTask(site.Name, _serviceName, _wmiUserName, _wmiPassword) + site.AddTask(new WinServiceCreateTask(site.Name, _serviceName) { Dependencies = _dependencies.ToArray(), UserName = _userName, diff --git a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceDeleteTask.cs b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceDeleteTask.cs index 88b0106b..48ed94d2 100644 --- a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceDeleteTask.cs +++ b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceDeleteTask.cs @@ -20,25 +20,15 @@ public class ProtoWinServiceDeleteTask : BaseProtoTask { readonly string _serviceName; - readonly string _wmiUserName; - readonly string _wmiPassword; - public ProtoWinServiceDeleteTask(string serviceName, string wmiUserName=null, string wmiPassword=null) + public ProtoWinServiceDeleteTask(string serviceName) { _serviceName = ReplaceTokens(serviceName); - if(!string.IsNullOrEmpty(wmiUserName)) - { - _wmiUserName = ReplaceTokens(wmiUserName); - } - if(!string.IsNullOrEmpty(wmiPassword)) - { - _wmiPassword = ReplaceTokens(wmiPassword); - } } public override void RegisterRealTasks(PhysicalServer site) { - site.AddTask(new WinServiceDeleteTask(site.Name, _serviceName, _wmiUserName, _wmiPassword)); + site.AddTask(new WinServiceDeleteTask(site.Name, _serviceName)); } } } \ No newline at end of file diff --git a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStartTask.cs b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStartTask.cs index e230fa99..bc508456 100644 --- a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStartTask.cs +++ b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStartTask.cs @@ -20,25 +20,15 @@ public class ProtoWinServiceStartTask : BaseProtoTask { readonly string _serviceName; - readonly string _wmiUserName; - readonly string _wmiPassword; - public ProtoWinServiceStartTask(string serviceName, string wmiUserName=null, string wmiPassword=null) + public ProtoWinServiceStartTask(string serviceName) { _serviceName = ReplaceTokens(serviceName); - if (!string.IsNullOrEmpty(wmiUserName)) - { - _wmiUserName = ReplaceTokens(wmiUserName); - } - if (!string.IsNullOrEmpty(wmiPassword)) - { - _wmiPassword = ReplaceTokens(wmiPassword); - } } public override void RegisterRealTasks(PhysicalServer s) { - s.AddTask(new WinServiceStartTask(s.Name, _serviceName, _wmiUserName, _wmiPassword)); + s.AddTask(new WinServiceStartTask(s.Name, _serviceName)); } } } \ No newline at end of file diff --git a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStopTask.cs b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStopTask.cs index 05f52f70..acecf999 100644 --- a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStopTask.cs +++ b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceStopTask.cs @@ -20,25 +20,15 @@ public class ProtoWinServiceStopTask : BaseProtoTask { readonly string _serviceName; - readonly string _wmiUserName; - readonly string _wmiPassword; - public ProtoWinServiceStopTask(string serviceName, string wmiUserName=null, string wmiPassword=null) + public ProtoWinServiceStopTask(string serviceName) { _serviceName = ReplaceTokens(serviceName); - if (!string.IsNullOrEmpty(wmiUserName)) - { - _wmiUserName = ReplaceTokens(wmiUserName); - } - if (!string.IsNullOrEmpty(wmiPassword)) - { - _wmiPassword = ReplaceTokens(wmiPassword); - } } public override void RegisterRealTasks(PhysicalServer s) { - s.AddTask(new WinServiceStopTask(s.Name, _serviceName, _wmiUserName, _wmiPassword)); + s.AddTask(new WinServiceStopTask(s.Name, _serviceName)); } } } \ No newline at end of file diff --git a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceTask.cs b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceTask.cs index b4c7e7d4..25df944c 100644 --- a/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceTask.cs +++ b/product/dropkick/Configuration/Dsl/WinService/ProtoWinServiceTask.cs @@ -20,8 +20,6 @@ public class ProtoWinServiceTask : { readonly ProtoServer _protoServer; readonly string _serviceName; - string _wmiUserName; - string _wmiPassword; public ProtoWinServiceTask(ProtoServer protoServer, string serviceName) { @@ -29,46 +27,39 @@ public ProtoWinServiceTask(ProtoServer protoServer, string serviceName) _serviceName = serviceName; } - public WinServiceOptions WithAuthentication(string wmiUserName, string wmiPassword) - { - _wmiUserName = wmiUserName; - _wmiPassword = wmiPassword; - return this; - } - public WinServiceOptions Do(Action registerAdditionalActions) { - _protoServer.RegisterProtoTask(new ProtoWinServiceStopTask(_serviceName, _wmiUserName, _wmiPassword)); + _protoServer.RegisterProtoTask(new ProtoWinServiceStopTask(_serviceName)); //child task registerAdditionalActions(_protoServer); - _protoServer.RegisterProtoTask(new ProtoWinServiceStartTask(_serviceName, _wmiUserName, _wmiPassword)); + _protoServer.RegisterProtoTask(new ProtoWinServiceStartTask(_serviceName)); return this; } public void Start() { - _protoServer.RegisterProtoTask(new ProtoWinServiceStartTask(_serviceName, _wmiUserName, _wmiPassword)); + _protoServer.RegisterProtoTask(new ProtoWinServiceStartTask(_serviceName)); } public void Stop() { - _protoServer.RegisterProtoTask(new ProtoWinServiceStopTask(_serviceName, _wmiUserName, _wmiPassword)); + _protoServer.RegisterProtoTask(new ProtoWinServiceStopTask(_serviceName)); } public WinServiceCreateOptions Create() { - var proto = new ProtoWinServiceCreateTask(new DotNetPath(), _serviceName, _wmiUserName, _wmiPassword); + var proto = new ProtoWinServiceCreateTask(new DotNetPath(), _serviceName); _protoServer.RegisterProtoTask(proto); return proto; } public void Delete() { - _protoServer.RegisterProtoTask(new ProtoWinServiceDeleteTask(_serviceName, _wmiUserName, _wmiPassword)); + _protoServer.RegisterProtoTask(new ProtoWinServiceDeleteTask(_serviceName)); } } } \ No newline at end of file diff --git a/product/dropkick/Configuration/Dsl/WinService/WinServiceOptions.cs b/product/dropkick/Configuration/Dsl/WinService/WinServiceOptions.cs index ce832547..7329c51b 100644 --- a/product/dropkick/Configuration/Dsl/WinService/WinServiceOptions.cs +++ b/product/dropkick/Configuration/Dsl/WinService/WinServiceOptions.cs @@ -20,7 +20,6 @@ public interface WinServiceOptions void Stop(); WinServiceCreateOptions Create(); void Delete(); - WinServiceOptions WithAuthentication(string userName, string password); WinServiceOptions Do(Action registerAdditionalActions); } } \ No newline at end of file diff --git a/product/dropkick/FileSystem/DotNetPath.cs b/product/dropkick/FileSystem/DotNetPath.cs index 60cc87df..8b6d7ff8 100644 --- a/product/dropkick/FileSystem/DotNetPath.cs +++ b/product/dropkick/FileSystem/DotNetPath.cs @@ -26,11 +26,6 @@ public class DotNetPath : Path #region Path Members public string GetPhysicalPath(PhysicalServer site, string path, bool forceLocalPath) - { - return this.GetPhysicalPath(site, path, forceLocalPath, null, null); - } - - public string GetPhysicalPath(PhysicalServer site, string path,bool forceLocalPath, string wmiUserName, string wmiPassword) { var standardizedPath = path; if (!IsUncPath(standardizedPath)) @@ -50,7 +45,7 @@ public string GetPhysicalPath(PhysicalServer site, string path,bool forceLocalPa if (shareMatch.Success) { var shareName = shareMatch.Groups["shareName"].Value; - serviceLocation = Win32Share.GetLocalPathForShare(site.Name, shareName, wmiUserName, wmiPassword); + serviceLocation = Win32Share.GetLocalPathForShare(site.Name, shareName); } var rest = shareMatch.Groups["rest"].Value; standardizedPath = System.IO.Path.Combine(serviceLocation, rest); diff --git a/product/dropkick/FileSystem/Path.cs b/product/dropkick/FileSystem/Path.cs index c02946a6..28e9d2e9 100644 --- a/product/dropkick/FileSystem/Path.cs +++ b/product/dropkick/FileSystem/Path.cs @@ -18,7 +18,6 @@ namespace dropkick.FileSystem public interface Path { string GetPhysicalPath(PhysicalServer server, string path, bool forceLocalPath); - string GetPhysicalPath(PhysicalServer server, string path, bool forceLocalPath, string wmiUserName, string wmiPassword); string Combine(string root, params string[] ex); string GetFullPath(string path); bool IsFile(string path); diff --git a/product/dropkick/Tasks/WinService/BaseServiceTask.cs b/product/dropkick/Tasks/WinService/BaseServiceTask.cs index 5f00ebac..3ced947c 100644 --- a/product/dropkick/Tasks/WinService/BaseServiceTask.cs +++ b/product/dropkick/Tasks/WinService/BaseServiceTask.cs @@ -19,24 +19,20 @@ namespace dropkick.Tasks.WinService public abstract class BaseServiceTask : BaseTask { - protected BaseServiceTask(string machineName, string serviceName, string wmiUserName, string wmiPassword) + protected BaseServiceTask(string machineName, string serviceName) { MachineName = machineName; ServiceName = serviceName; - WmiUserName = wmiUserName; - WmiPassword = wmiPassword; } public string MachineName { get; set; } public string ServiceName { get; set; } - public string WmiUserName { get; set; } - public string WmiPassword { get; set; } protected bool ServiceIsRunning() { try { - if (string.IsNullOrEmpty(WmiUserName) || string.IsNullOrEmpty(WmiPassword)) + if (!dropkick.Wmi.WmiService.AuthenticationSpecified) { using (var c = new ServiceController(ServiceName, MachineName)) { @@ -45,7 +41,7 @@ protected bool ServiceIsRunning() } else { - var status = dropkick.Wmi.WmiService.QueryService(MachineName, ServiceName, WmiUserName, WmiPassword); + var status = dropkick.Wmi.WmiService.QueryService(MachineName, ServiceName); switch (status) { case Wmi.ServiceReturnCode.ServiceAlreadyRunning: @@ -66,7 +62,7 @@ protected bool ServiceExists() { try { - if(string.IsNullOrEmpty(WmiUserName) || string.IsNullOrEmpty(WmiPassword)) + if(!dropkick.Wmi.WmiService.AuthenticationSpecified) { using (var c = new ServiceController(ServiceName, MachineName)) { @@ -76,7 +72,7 @@ protected bool ServiceExists() } else { - var status = dropkick.Wmi.WmiService.QueryService(MachineName, ServiceName, WmiUserName, WmiPassword); + var status = dropkick.Wmi.WmiService.QueryService(MachineName, ServiceName); switch(status) { case Wmi.ServiceReturnCode.DependentServicesRunning: diff --git a/product/dropkick/Tasks/WinService/WinServiceCreateTask.cs b/product/dropkick/Tasks/WinService/WinServiceCreateTask.cs index c42dbe62..98770e5e 100644 --- a/product/dropkick/Tasks/WinService/WinServiceCreateTask.cs +++ b/product/dropkick/Tasks/WinService/WinServiceCreateTask.cs @@ -24,8 +24,8 @@ public class WinServiceCreateTask : //TODO: should be injected readonly PromptService _prompt = new ConsolePromptService(); - public WinServiceCreateTask(string machineName, string serviceName, string wmiUserName=null, string wmiPassword=null) - : base(machineName, serviceName, wmiUserName, wmiPassword) + public WinServiceCreateTask(string machineName, string serviceName) + : base(machineName, serviceName) { } @@ -70,7 +70,7 @@ public override DeploymentResult Execute() displayName = ServiceName; ServiceReturnCode returnCode = WmiService.Create(MachineName, ServiceName, displayName, ServiceLocation, - StartMode, UserName, Password, Dependencies, WmiUserName, WmiPassword); + StartMode, UserName, Password, Dependencies); if (returnCode != ServiceReturnCode.Success) result.AddAlert("Create service returned {0}".FormatWith(returnCode.ToString())); diff --git a/product/dropkick/Tasks/WinService/WinServiceDeleteTask.cs b/product/dropkick/Tasks/WinService/WinServiceDeleteTask.cs index 3cf96ef7..00ea78dd 100644 --- a/product/dropkick/Tasks/WinService/WinServiceDeleteTask.cs +++ b/product/dropkick/Tasks/WinService/WinServiceDeleteTask.cs @@ -18,7 +18,7 @@ namespace dropkick.Tasks.WinService public class WinServiceDeleteTask : BaseServiceTask { - public WinServiceDeleteTask(string machineName, string serviceName, string wmiUserName=null, string wmiPassword=null) : base(machineName, serviceName, wmiUserName, wmiPassword) + public WinServiceDeleteTask(string machineName, string serviceName) : base(machineName, serviceName) { } @@ -47,7 +47,7 @@ public override DeploymentResult Execute() } else { - ServiceReturnCode returnCode = WmiService.Delete(MachineName, ServiceName, WmiUserName, WmiPassword); + ServiceReturnCode returnCode = WmiService.Delete(MachineName, ServiceName); if(returnCode != ServiceReturnCode.Success) { result.AddAlert("Deleting service '{0}' failed: '{1}'".FormatWith(ServiceName, returnCode)); diff --git a/product/dropkick/Tasks/WinService/WinServiceStartTask.cs b/product/dropkick/Tasks/WinService/WinServiceStartTask.cs index ed4e63d5..7fb22bde 100644 --- a/product/dropkick/Tasks/WinService/WinServiceStartTask.cs +++ b/product/dropkick/Tasks/WinService/WinServiceStartTask.cs @@ -9,8 +9,8 @@ namespace dropkick.Tasks.WinService public class WinServiceStartTask : BaseServiceTask { - public WinServiceStartTask(string machineName, string serviceName, string wmiUserName=null, string wmiPassword=null) - : base(machineName, serviceName, wmiUserName, wmiPassword) + public WinServiceStartTask(string machineName, string serviceName) + : base(machineName, serviceName) { } @@ -43,7 +43,7 @@ public override DeploymentResult Execute() if (ServiceExists()) { - if(string.IsNullOrEmpty(WmiUserName) || string.IsNullOrEmpty(WmiPassword)) + if(!dropkick.Wmi.WmiService.AuthenticationSpecified) { using (var c = new ServiceController(ServiceName, MachineName)) { @@ -79,7 +79,7 @@ public override DeploymentResult Execute() { try { - var returnCode = dropkick.Wmi.WmiService.Start(MachineName, ServiceName, WmiUserName, WmiPassword); + var returnCode = dropkick.Wmi.WmiService.Start(MachineName, ServiceName); switch(returnCode) { case Wmi.ServiceReturnCode.Success: @@ -95,7 +95,7 @@ public override DeploymentResult Execute() } break; default: - result.AddError("Failed to start service '{0}', most likely due to a logon issue.".FormatWith(ServiceName)); + result.AddError("Failed to start service '{0}', most likely due to a logon issue, result: {1}".FormatWith(ServiceName, returnCode)); LogCoarseGrain("The service '{0}' did not start, most likely due to a logon issue.", ServiceName); break; } diff --git a/product/dropkick/Tasks/WinService/WinServiceStopTask.cs b/product/dropkick/Tasks/WinService/WinServiceStopTask.cs index 6e1ad33c..99f0b8b9 100644 --- a/product/dropkick/Tasks/WinService/WinServiceStopTask.cs +++ b/product/dropkick/Tasks/WinService/WinServiceStopTask.cs @@ -23,8 +23,8 @@ namespace dropkick.Tasks.WinService public class WinServiceStopTask : BaseServiceTask { - public WinServiceStopTask(string machineName, string serviceName, string wmiUserName=null, string wmiPassword=null) - : base(machineName, serviceName, wmiUserName, wmiPassword) + public WinServiceStopTask(string machineName, string serviceName) + : base(machineName, serviceName) { } @@ -57,7 +57,7 @@ public override DeploymentResult Execute() if (ServiceExists()) { - if(string.IsNullOrEmpty(WmiUserName) || string.IsNullOrEmpty(WmiPassword)) + if(!dropkick.Wmi.WmiService.AuthenticationSpecified) { using (var c = new ServiceController(ServiceName, MachineName)) { @@ -84,7 +84,7 @@ public override DeploymentResult Execute() } else { - var status = dropkick.Wmi.WmiService.Stop(MachineName, ServiceName, WmiUserName, WmiPassword); + var status = dropkick.Wmi.WmiService.Stop(MachineName, ServiceName); switch (status) { case Wmi.ServiceReturnCode.StatusServiceExists: diff --git a/product/dropkick/Wmi/Win32Share.cs b/product/dropkick/Wmi/Win32Share.cs index d26b8b05..96857d7b 100644 --- a/product/dropkick/Wmi/Win32Share.cs +++ b/product/dropkick/Wmi/Win32Share.cs @@ -73,10 +73,10 @@ public static ShareReturnCode Delete(string serverName, string shareName) return ShareReturnCode.UnknownFailure; } - public static string GetLocalPathForShare(string serverName, string shareName, string wmiUserName=null, string wmiPassword=null) + public static string GetLocalPathForShare(string serverName, string shareName) { var query = new WqlObjectQuery("select Name, Path from Win32_Share"); - var scope = WmiHelper.Connect(serverName, wmiUserName, wmiPassword); + var scope = WmiHelper.Connect(serverName); using (var search = new ManagementObjectSearcher(scope, query)) { diff --git a/product/dropkick/Wmi/WmiHelper.cs b/product/dropkick/Wmi/WmiHelper.cs index b12b9d9c..a72724cd 100644 --- a/product/dropkick/Wmi/WmiHelper.cs +++ b/product/dropkick/Wmi/WmiHelper.cs @@ -5,7 +5,18 @@ namespace dropkick.Wmi public class WmiHelper { - public static ManagementScope Connect(string machineName, string userName=null, string password=null) + [ThreadStatic] + private static string _wmiUserName; + + [ThreadStatic] + private static string _wmiPassword; + + public static bool AuthenticationSpecified + { + get { return !string.IsNullOrEmpty(_wmiUserName) || !string.IsNullOrEmpty(_wmiPassword); } + } + + public static ManagementScope Connect(string machineName) { var scope = new ManagementScope(@"\\{0}\root\cimv2".FormatWith(machineName)) { @@ -13,42 +24,42 @@ public static ManagementScope Connect(string machineName, string userName=null, { Impersonation = ImpersonationLevel.Impersonate, EnablePrivileges = true, - Username = userName, - Password = password + Username = _wmiUserName, + Password = _wmiPassword } }; - + try { scope.Connect(); } catch (Exception exc) { - if(string.IsNullOrEmpty(userName)) + if(string.IsNullOrEmpty(_wmiUserName)) { throw new SystemException("Problem connecting WMI scope on " + machineName + " with current user account.", exc); } else { - throw new SystemException("Problem connecting WMI scope on " + machineName + " with user account " + userName, exc); + throw new SystemException("Problem connecting WMI scope on " + machineName + " with user account " + _wmiUserName, exc); } } return scope; } - static ManagementObject GetInstanceByName(string machineName, string className, string name, string userName=null, string password=null) { + static ManagementObject GetInstanceByName(string machineName, string className, string name) { var query = "SELECT * FROM " + className + " WHERE Name = '" + name + "'"; - foreach (ManagementObject manObject in Query(machineName,query, userName, password)) { + foreach (ManagementObject manObject in Query(machineName,query)) { return manObject; } return null; } - public static ManagementObjectCollection Query(string machineName, string query, string userName=null, string password=null) + public static ManagementObjectCollection Query(string machineName, string query) { - ManagementScope scope = Connect(machineName, userName, password); + ManagementScope scope = Connect(machineName); var queryObj = new ObjectQuery(query); var searcher = new ManagementObjectSearcher(scope, queryObj); ManagementObjectCollection results = searcher.Get(); @@ -58,9 +69,9 @@ public static ManagementObjectCollection Query(string machineName, string query, - static ManagementClass GetStaticByName(string machineName, string className, string userName=null, string password=null) + static ManagementClass GetStaticByName(string machineName, string className) { - ManagementScope scope = Connect(machineName, userName, password); + ManagementScope scope = Connect(machineName); var getOptions = new ObjectGetOptions(); var path = new ManagementPath(className); var manClass = new ManagementClass(scope, path, getOptions); @@ -73,11 +84,6 @@ public static int InvokeInstanceMethod(string machineName, string className, str return InvokeInstanceMethod(machineName, className, name, methodName, null); } - public static int InvokeInstanceMethodWithAuthentication(string machineName, string className, string name, string methodName, string userName, string password) - { - return InvokeInstanceMethodWithAuthentication(machineName, className, name, methodName, userName, password, null); - } - public static int InvokeInstanceMethod(string machineName, string className, string name, string methodName, object[] parameters) { @@ -93,21 +99,6 @@ public static int InvokeInstanceMethod(string machineName, string className, str } } - public static int InvokeInstanceMethodWithAuthentication(string machineName, string className, string name, string methodName, - string userName, string password, object[] parameters) - { - try - { - ManagementObject manObject = GetInstanceByName(machineName, className, name, userName, password); - object result = manObject.InvokeMethod(methodName, parameters); - return Convert.ToInt32(result); - } - catch - { - return -1; - } - } - public static int InvokeStaticMethod(string machineName, string className, string methodName) { return InvokeStaticMethod(machineName, className, methodName, null); @@ -130,21 +121,10 @@ public static int InvokeStaticMethod(string machineName, string className, strin } } - public static int InvokeStaticMethodWithAuthentication(string machineName, string className, string methodName, - object[] parameters, string wmiUserName, string wmiPassword) + public static void WithAuthentication(string remoteUserName, string remotePassword) { - try - { - using (var managementClass = GetStaticByName(machineName, className, wmiUserName, wmiPassword)) - { - object result = managementClass.InvokeMethod(methodName, parameters); - return Convert.ToInt32(result); - } - } - catch - { - return -1; - } + _wmiUserName = remoteUserName; + _wmiPassword = remotePassword; } } } \ No newline at end of file diff --git a/product/dropkick/Wmi/WmiService.cs b/product/dropkick/Wmi/WmiService.cs index 8949b557..89accf64 100644 --- a/product/dropkick/Wmi/WmiService.cs +++ b/product/dropkick/Wmi/WmiService.cs @@ -8,11 +8,16 @@ namespace dropkick.Wmi public class WmiService { const string CLASSNAME = "Win32_Service"; - //private char NULL_VALUE = char(0); + //private char NULL_VALUE = char(0); + + public static bool AuthenticationSpecified + { + get { return WmiHelper.AuthenticationSpecified; } + } public static ServiceReturnCode Create(string machineName, string serviceName, string serviceDisplayName, string serviceLocation, ServiceStartMode startMode, string userName, - string password, string[] dependencies, string wmiUserName=null, string wmiPassword=null) + string password, string[] dependencies) { if (userName != null && userName.IndexOf('\\') < 0) { @@ -39,7 +44,7 @@ public static ServiceReturnCode Create(string machineName, string serviceName, s null, // LoadOrderGroupDependencies | Load Order Dependencies dependencies // ServiceDependencies }; - return (ServiceReturnCode) WmiHelper.InvokeStaticMethodWithAuthentication(machineName, CLASSNAME, methodName, parameters, wmiUserName, wmiPassword); + return (ServiceReturnCode) WmiHelper.InvokeStaticMethod(machineName, CLASSNAME, methodName, parameters); } catch { @@ -47,13 +52,13 @@ public static ServiceReturnCode Create(string machineName, string serviceName, s } } - public static ServiceReturnCode Delete(string machineName, string serviceName, string wmiUserName=null, string wmiPassword=null) + public static ServiceReturnCode Delete(string machineName, string serviceName) { try { string methodName = "Delete"; return - (ServiceReturnCode) WmiHelper.InvokeInstanceMethodWithAuthentication(machineName, CLASSNAME, serviceName, methodName, wmiUserName, wmiPassword); + (ServiceReturnCode) WmiHelper.InvokeInstanceMethod(machineName, CLASSNAME, serviceName, methodName); } catch { @@ -61,13 +66,13 @@ public static ServiceReturnCode Delete(string machineName, string serviceName, s } } - public static ServiceReturnCode Start(string machineName, string serviceName, string wmiUserName, string wmiPassword) + public static ServiceReturnCode Start(string machineName, string serviceName) { try { string methodName = "StartService"; return - (ServiceReturnCode) WmiHelper.InvokeInstanceMethodWithAuthentication(machineName, CLASSNAME, serviceName, methodName, wmiUserName, wmiPassword); + (ServiceReturnCode) WmiHelper.InvokeInstanceMethod(machineName, CLASSNAME, serviceName, methodName); } catch { @@ -75,13 +80,13 @@ public static ServiceReturnCode Start(string machineName, string serviceName, st } } - public static ServiceReturnCode Stop(string machineName, string serviceName, string wmiUserName, string wmiPassword) + public static ServiceReturnCode Stop(string machineName, string serviceName) { try { string methodName = "StopService"; return - (ServiceReturnCode) WmiHelper.InvokeInstanceMethodWithAuthentication(machineName, CLASSNAME, serviceName, methodName, wmiUserName, wmiPassword); + (ServiceReturnCode) WmiHelper.InvokeInstanceMethod(machineName, CLASSNAME, serviceName, methodName); } catch { @@ -103,13 +108,13 @@ public static ServiceReturnCode Pause(string machineName, string serviceName) } } - public static ServiceReturnCode QueryService(string machineName, string serviceName, string userName, string password) + public static ServiceReturnCode QueryService(string machineName, string serviceName) { try { string methodName = "InterrogateService"; return - (ServiceReturnCode) WmiHelper.InvokeInstanceMethodWithAuthentication(machineName, CLASSNAME, serviceName, methodName, userName, password); + (ServiceReturnCode) WmiHelper.InvokeInstanceMethod(machineName, CLASSNAME, serviceName, methodName); } catch { @@ -129,6 +134,11 @@ public static ServiceReturnCode Resume(string machineName, string serviceName) { return ServiceReturnCode.UnknownFailure; } - } + } + + public static void WithAuthentication(string remoteUserName, string remotePassword) + { + WmiHelper.WithAuthentication(remoteUserName, remotePassword); + } } } \ No newline at end of file diff --git a/product/dropkick/dropkick.csproj b/product/dropkick/dropkick.csproj index dc01c0dc..e980502f 100644 --- a/product/dropkick/dropkick.csproj +++ b/product/dropkick/dropkick.csproj @@ -91,6 +91,7 @@ +