Managing Windows Services from a Remote System | CodeGuru

Managing Windows Services from a Remote System

A simple command line utility for managing Windows services from a remote system . Environment: VC++6.0, Windows NT 4.0 and Windows 2000 Introduction Most of us use the Services Manager tool to start and stop Windows Services. To install and uninstall, we need to run a Service program as a normal process with specific command-line […]

Written By
CodeGuru Staff
CodeGuru Staff
Aug 16, 2002
3 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

A simple command line utility for managing Windows services from a remote system

.

Environment: VC++6.0, Windows NT 4.0 and Windows 2000

Introduction

Most of us use the Services Manager tool to start and stop Windows Services. To install and uninstall, we need to run a Service program as a normal process with specific command-line parameters. For example, if we have a service executable called as “MyService.exe”, we can install this as a service by executing this with a command line parameter “-Service”. To uninstall, we need to pass “-UnregServer” as the parameter.

The following code provides a simple utility for Windows Services Management from custom applications. Using this code, you can Install, Uninstall, Start, Stop, and Query the status of a service running on the local or a remote system, provided the user has administrative privileges for that system.

int main(int argc, char* argv[])
{
  if(argc < 3)
  {
    printf("USAGE:  ServiceInstaller [install / uninstall _
        / start / stop] [Service Name]");
    printf(" [Computer's Network Name](optional)n");
    return 0;
  }

  char *pSysName = NULL;
  char *pSvcPath = NULL;

  if(argc == 4)
  {
    pSysName = new char[50];      //if remote system
    strcpy(pSysName, argv[3]);

    ImpersonateUser();
  }

    //access service control manager
    SC_HANDLE hSCM = ::OpenSCManager(pSysName,
                       SERVICES_ACTIVE_DATABASE,
                       SC_MANAGER_ALL_ACCESS);

    if (hSCM == 0)
    {
      printf("ERROR: UNABLE TO OPEN SERVICE MANAGERn");
      PrintError(GetLastError());
      return;
    }

  if(!strcmp(argv[1],"install"))
  {
    //to install we need the path for the executable
    printf("Please enter path of the Executablen");
    pSvcPath = new char[MAX_PATH];
    scanf("%s",pSvcPath);

// Computer's network name, service name, and path of
// the executable
    Install(hSCM, argv[2], path);
    delete[] path;
  }
  else if(!strcmp(argv[1],"uninstall"))
  {
    Uninstall(hSCM, argv[2]);
  }
  else if(!strcmp(argv[1],"start"))
  {
    StartSvc(hSCM, argv[2]);
  }
  else if(!strcmp(argv[1],"stop"))
  {
    StopSvc(hSCM, argv[2]);
  }
  else if(!strcmp(argv[1],"status"))
  {
    QuerySvc(hSCM, argv[2]);
  }
  else
  {
    printf("WARNING: Bad commandn");
  }

::CloseServiceHandle(hSCM);

  delete[] pName;

return 0;
}

The following is a helper function, which is used to impersonate the logged-in user in case of a remote system access.

void ImpersonateUser()
{
  //prepare to access remote system

  DWORD id = GetCurrentProcessId();
  HANDLE hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id);

  HANDLE t;

  BOOL b = OpenProcessToken( hp,
                             TOKEN_QUERY | TOKEN_DUPLICATE ,
                             &t);

  if(!ImpersonateLoggedOnUser(t))
  {
    PrintError(GetLastError());
    return;
  }
}

In case of a Windows error, this function helps decode the error code to an user-understandable error string.

void PrintError(DWORD code)
{
     LPTSTR serr;

     if(::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
      FORMAT_MESSAGE_FROM_SYSTEM,
      NULL,
      code,
      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
      (LPTSTR)&serr,
      0,
      NULL) == 0)
  {
    printf("Unknown Errorn");
  }
    else
  {
    printf("Error : %sn", serr);
    LocalFree(serr);
  }
}

It is a simple command-line application, which calls different functions based on the first command-line parameter. The second parameter is the service name, and the third parameter is the optional network name of the computer you are trying to access. If you are providing the remote system name, you will have to have the administrative privileges for that system.

Installing a Service

Here we are creating the service using Windows’ CreateService function. We are providing the user with a “manual start” option; the other option we could have provided was SERVICE_AUTO_START, which will get the service started automatically by the SCM at the system startup.

void Install(SC_HANDLE hSCM, char *szSvcName,char *szFilePath)
{
  // Service installation

  SC_HANDLE hService = ::CreateService(
  hSCM, szSvcName, szSvcName,
  SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
  // by default we are providing the user with
  // manual-start option,
  SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE,
  szFilePath, NULL, NULL, NULL, NULL, NULL);

  if (hService == NULL)
  {
    printf("ERROR: COULDN'T CREATE SERVICEn");
    return;
  }

  ::CloseServiceHandle(hService);
}
Advertisement

Uninstalling a Service

To uninstall a service, we need to do three things. First, get a handle on the service with SERVICE_STOP and DELETE access rights, call the ControlService function with the SERVICE_CONTROL_STOP flag that sends a quit message to the service, and then call the DeleteService method to remove the service from the list of available services.

void Uninstall(SC_HANDLE hSCM, char *szSvcName)
{
    //get a handle to the service
    SC_HANDLE hService = ::OpenService(hSCM,
                                       szSvcName,
                                       SERVICE_STOP | DELETE);

    if (hService == NULL)
    {
        printf("ERROR: COULDN'T OPEN SERVICEn");
        return;
    }

    // let us first stop the service
    SERVICE_STATUS status;
    ::ControlService(hService, SERVICE_CONTROL_STOP, &status);

    //Print the status of the service
    PrintStatus(status);

   // now uninstall the service
    BOOL bDelete = ::DeleteService(hService);
    ::CloseServiceHandle(hService);

    if (!bDelete)
        printf("WARNING: SERVICE COULD NOT BE DELETEDn");
}

Now let us take a look at the PrintStatus method. This method prints the current state of the service given the SERVICE_STATUS structure.

void PrintStatus(SERVICE_STATUS sc)
{
  switch(sc.dwCurrentState)
  {
    case SERVICE_STOPPED :
         printf("The service is not running.");
         break;
    case SERVICE_START_PENDING :
         printf("The service is starting.");
         break;
    case SERVICE_STOP_PENDING:
         printf("The service is stopping. ");
         break;
    case SERVICE_RUNNING:
         printf("The service is running. ");
         break;
    case SERVICE_CONTINUE_PENDING:
         printf("The service continue is pending.");
         break;
    case SERVICE_PAUSE_PENDING:
         printf("The service pause is pending. ");
         break;
    case SERVICE_PAUSED:
         printf("The service is paused.");
         break;
    default:
         printf("Status Unknown");
         break;
  }
}

Starting a Service

To start a service, you need to get a handle to the service providing the SERVICE_START flag to the OpenService function, and call the StartService function. This function takes a service handle, the number of arguments as an integer, and a string-list. After starting the service, we shall query the status of the service.

void StartSvc(SC_HANDLE hSCM, char *szSvcName)
{
    SC_HANDLE hService = ::OpenService(hSCM,
                                       szSvcName,
                                       SERVICE_START);

    if (hService == NULL)
    {
        printf("ERROR: COULDN'T ACCESS SERVICEn");
        return;
    }

    //no arguments
    if(::StartService(hService, 0, NULL)==0)
    {
    PrintError(GetLastError());
     }

    ::CloseServiceHandle(hService);

     QuerySvc(szNetworkName, szSvcName);
}
Advertisement

Querying the Current Status of the Service

When we open the Windows Service Manager, we get to know the status of each service. Similarly, we have to have a way to query the status of the service programmatically. The code listed below provides this utility. After we get the Service handle, we will call QueryService function to get the service status.

void QuerySvc(SC_HANDLE hSCM,, char *szSvcName)
{
    //get service handle
    SC_HANDLE hService = ::OpenService(hSCM, szSvcName,
        SERVICE_QUERY_STATUS);

    if (hService == NULL)
    {
        printf("ERROR: COULDN'T OPEN SERVICEn");
        return;
    }

  SERVICE_STATUS status;

    //query status
  if(!QueryServiceStatus(hService,&status))
  {
    ::CloseServiceHandle(hSCM);
    PrintError(GetLastError());
  }

  PrintStatus(status);

    ::CloseServiceHandle(hService);
}

Stopping the Service

To stop a service, we call the ControlService with the SERVICE_CONTROL_STOP flag.

void StopSvc(SC_HANDLE hSCM,, char *szSvcName)
{
    SC_HANDLE hService = ::OpenService(hSCM,
                                       szSvcName,
                                       SERVICE_STOP);

    if (hService == NULL)
    {
        printf("ERROR: COULDN'T OPEN SERVICEn");
        return;
    }

    SERVICE_STATUS status;
    if(!::ControlService(hService,
                         SERVICE_CONTROL_STOP,
                         &status))
    printf("ERROR: COULDN'T STOP SERVICEn");


    ::CloseServiceHandle(hService);

    QuerySvc(szNetworkName, szSvcName);
}

Downloads

Download source – 6 Kb

CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.