Managing Windows services with Symfony/Process and PHP
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.
Posted on October 29, 2012, in php, Technology and tagged behat, command line parser, service status, services, software, Symfony, windows. Bookmark the permalink. 1 Comment.
























Pingback: Gonzalo Ayuso: Managing Windows services with Symfony/Process and PHP : Atom Wire