Sometimes I need to stop/start remote Windows services with PHP. It’s quite easy to do it with net commnand. This command is a tool for administration of Samba and remote CIFS servers. It’s pretty straightforward to handle them from Linux command line:
net rpc service --help Usage: net rpc service list View configured Win32 services net rpc service start Start a service net rpc service stop Stop a service net rpc service pause Pause a service net rpc service resume Resume a service net rpc service status View current status of a service net rpc service delete Deletes a service net rpc service create Creates a service
Today we are going to create a PHP wrapper for this tool. Our NetService library will have two classes: One Parser and one Service class.
The Parser’s responsibility will be create the command line instruction. I will use Behat in the developing process of Parser class. Here we can see the feature file:
Feature: command line parser Scenario: net service list Given windows server host called "windowshost.com" And credentials are "myDomanin/user%password" And action is "list" Then command line is "net rpc service list -S windowshost.com -U myDomanin/user%password" Scenario: net service start Given windows server host called "windowshost.com" And service name called "ServiceName" And credentials are "myDomanin/user%password" And action is "start" Then command line is "net rpc service start ServiceName -S windowshost.com -U myDomanin/user%password" Scenario: net service stop Given windows server host called "windowshost.com" And service name called "ServiceName" And credentials are "myDomanin/user%password" And action is "stop" Then command line is "net rpc service stop ServiceName -S windowshost.com -U myDomanin/user%password" Scenario: net service pause Given windows server host called "windowshost.com" And service name called "ServiceName" And credentials are "myDomanin/user%password" And action is "pause" Then command line is "net rpc service pause ServiceName -S windowshost.com -U myDomanin/user%password" Scenario: net service resume Given windows server host called "windowshost.com" And service name called "ServiceName" And credentials are "myDomanin/user%password" And action is "resume" Then command line is "net rpc service resume ServiceName -S windowshost.com -U myDomanin/user%password" Scenario: net service status Given windows server host called "windowshost.com" And service name called "ServiceName" And credentials are "myDomanin/user%password" And action is "status" Then command line is "net rpc service status ServiceName -S windowshost.com -U myDomanin/user%password"
The implementation of the feature file:
namespace NetService; class Parser { private $host; private $credentials; public function __construct($host, $credentials) { $this->host = $host; $this->credentials = $credentials; } public function getCommandLineForAction($action, $service = NULL) { if (!is_null($service)) $service = " {$service}"; return "net rpc service {$action}{$service} -S {$this->host} -U {$this->credentials}"; } }
and finally our Service class:
namespace NetService; use Symfony\Component\Process\Process, NetService\Parser; class Service { private $parser; private $timeout; const START = 'start'; const STOP = 'stop'; const STATUS = 'status'; const LIST_SERVICES = 'list'; const PAUSE = 'pause'; const RESUME = 'resume'; const DEFAULT_TIMEOUT = 3600; public function __construct(Parser $parser) { $this->parser = $parser; $this->timeout = self::DEFAULT_TIMEOUT; } public function start($service) { return $this->runProcess($this->parser->getCommandLineForAction(self::START, $service)); } public function stop($service) { return $this->runProcess($this->parser->getCommandLineForAction(self::STOP, $service)); } public function pause($service) { return $this->runProcess($this->parser->getCommandLineForAction(self::PAUSE, $service)); } public function resume($service) { return $this->runProcess($this->parser->getCommandLineForAction(self::RESUME, $service)); } public function status($service) { return $this->runProcess($this->parser->getCommandLineForAction(self::STATUS, $service)); } public function listServices() { return $this->runProcess($this->parser->getCommandLineForAction(self::LIST_SERVICES)); } public function isRunning($service) { $status = explode("\n", $this->status($service)); if (isset($status[0]) && strpos(strtolower($status[0]), "running") !== FALSE) { return TRUE; } else { return FALSE; } } public function setTimeout($timeout) { $this->timeout = $timeout; } private function runProcess($commandLine) { $process = new Process($commandLine); $process->setTimeout($this->timeout); $process->run(); if (!$process->isSuccessful()) { throw new RuntimeException($process->getErrorOutput()); } return $process->getOutput(); } private function parseStatus($status) { return explode("\n", $status); } }
And that’s all. Now a couple of examples:
include __DIR__ . '/../vendor/autoload.php'; use NetService\Service, NetService\Parser; $host = 'windowshost.com'; $serviceName = 'ServiceName'; $credentials = '{domain}/{user}%{password}'; $service = new Service(new Parser($host, $credentials)); if ($service->isRunning($serviceName)) { echo "Service is running. Let's stop"; $service->stop($serviceName); } else { echo "Service isn't running. Let's start"; $service->start($serviceName); } //dumps status output echo $service->status($serviceName);
include __DIR__ . '/../vendor/autoload.php'; use NetService\Service, NetService\Parser; $host = 'windowshost.com'; $credentials = '{domain}/{user}%{password}'; $service = new Service(new Parser($host, $credentials)); echo $service->listServices();
You can see the full code in github here. The package is also available for composer at Packaist.