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.