Remotely Installing Services

47 views
Skip to first unread message

Travis

unread,
Oct 28, 2009, 3:15:10 PM10/28/09
to masstransit-discuss
I'm looking at creating a method were our build system can copy the
services over to the staging machines and install the service. A
couple of options I've looked at are below but I wondered if anyone
had already done this.

- Modify TopShelf to do this on a remote machine - not sure it's
easily possible because of the service installation stuff in place
might not be able to executed remotely. However, updating a remote
registery for the custom actions looks doable.

- Use WMI to execute the "service -install" on the remote machine
(http://www.dalun.com/blogs/05.09.2007.htm)

- Use PsExec (http://technet.microsoft.com/en-us/sysinternals/
bb897553.aspx)

- Modify a "copy and proxy" method for remoting (http://netcode.ru/
dotnet/?lang=&katID=30&skatID=273&artID=7456)

Whatever I do will be built into our nant-based build system (likely
as a custom task) and then possibly included in a tool to install/
update new instances.

So has anyone come up with a solution for this already or have any
other bright ideas?

-Travis

Dru Sellers

unread,
Oct 28, 2009, 10:44:40 PM10/28/09
to masstrans...@googlegroups.com
I would love to hear what you end up doing. though it most likely won't end up in topshelf, it would certainly end up in my deployment stuff over at dropkick.

having the services remotely installable is on my wishlist and that is where I would implement it. :)

right now I considered either PS2 or PsExec. If you can get the WMI stuff to work in C# that would be AWESOME SAUCE!!

-d

Travis Smith

unread,
Oct 29, 2009, 9:30:22 AM10/29/09
to masstrans...@googlegroups.com
I have made a first run at this... it's a collection of service actions (start/stop), copying files, and running remote commands via WMI. You use the "Service Name" as the key to start/stop services.

Also, I was going to cross post this on dropkick but it appears you don't have a list for it Dru.

  <target name="copy-and-install">
    <service action="stop" service="Service1" machine="remote1" />
    <copy todir="\\remote1\C$\service1\">
      <fileset basedir="C:\my\Trunk\Services\bin\Debug">
        <include name="**/*" />
      </fileset>
    </copy>
    <remoteexec machine="remote1" command="C:\service1\service1.exe -install" />
    <service action="start" service="Service1" machine="devapp1" />
  </target>

using System;
using System.Management;
using NAnt.Core;
using NAnt.Core.Attributes;

namespace My.NAntTasks
{
    [TaskName("remoteexec")]
    public class ExecuteRemoteCommand : Task
    {
        #region Task Attributes
        [TaskAttribute("machine")]
        public string Machine { get; set; }

        [TaskAttribute("command")]
        [StringValidator(AllowEmpty = false)]
        public string CommandLine { get; set; }

        public string RemoteUser { get; set; }
       
        public string RemotePassword { get; set; }
        #endregion

        public ExecuteRemoteCommand()
        {
            Machine = Environment.MachineName;
        }

        protected override void ExecuteTask()
        {
            var logger = new LogWriter(this, Level.Info, null);

            // also allow for remote user/password
            ConnectionOptions connOptions = new ConnectionOptions();
            connOptions.Impersonation = ImpersonationLevel.Impersonate;
            connOptions.EnablePrivileges = true;

            ManagementScope manScope = new ManagementScope(String.Format(@"\\{0}\ROOT\CIMV2", Machine), connOptions);
            manScope.Connect();

            ObjectGetOptions objectGetOptions = new ObjectGetOptions();
            ManagementPath managementPath = new ManagementPath("Win32_Process");
            ManagementClass processClass = new ManagementClass(manScope, managementPath, objectGetOptions);

            ManagementBaseObject inParams = processClass.GetMethodParameters("Create");

            inParams["CommandLine"] = CommandLine;
            ManagementBaseObject outParams = processClass.InvokeMethod("Create", inParams, null);

            int returnVal = Convert.ToInt32(outParams["returnValue"]);

            switch (returnVal)
            {
                case 2:
                    throw new Exception("Access is denied.");

                case 3:
                    throw new Exception("Insufficient privileges.");

                case 8:
                    throw new Exception("Unknown failure.");

                case 9:
                    throw new Exception("Path not found.");

                case 21:
                    throw new Exception("Invalid parameter");
            }

            logger.WriteLine("Command executed on " + Machine);
        }
    }
}

----

using System;
using System.ServiceProcess;
using NAnt.Core;
using NAnt.Core.Attributes;

namespace My.NAntTasks
{
    [TaskName("service")]
    public class ServiceManager : Task
    {
        #region Task Attributes
        [TaskAttribute("action")]
        [StringValidator(AllowEmpty = false)]
        public string Action { get; set; }

        [TaskAttribute("machine")]
        public string Machine { get; set; }

        [TaskAttribute("service")]
        [StringValidator(AllowEmpty = false)]
        public string Service { get; set; }
        #endregion

        public ServiceManager()
        {
            Machine = Environment.MachineName;
        }

        protected override void ExecuteTask()
        {
            var logger = new LogWriter(this, Level.Info, null);

            if (Action == "stop")
            {
                using (var controller = new ServiceController(Service, Machine))
                {
                    if (controller.Status == ServiceControllerStatus.Running)
                    {
                        controller.Stop();
                        logger.WriteLine("Stopping " + Service);
                        controller.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(30));
                    }
                }
            }
            else if (Action == "start")
            {
                using (var controller = new ServiceController(Service, Machine))
                {
                    if (controller.Status == ServiceControllerStatus.Stopped)
                    {
                        controller.Start();
                        logger.WriteLine("Starting " + Service);
                        controller.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(30));

Dru Sellers

unread,
Nov 1, 2009, 9:46:46 AM11/1/09
to masstrans...@googlegroups.com
its in dropkick rev 115. going to keep adding some tweaks to it but thanks!!! soon MT will have remote machine deployability thanks to your awesomeness!
-d
Reply all
Reply to author
Forward
0 new messages