Using Powershell and TopShelf to install your C# service


As a supporter of Developers I often have to install and re-install Windows services.  In support of this I ask developers to utilize the following nuget package: TopShelf

This utility is very handy it makes installing a service and troubleshooting a C# service much easier.   Some of the things I like most is that you can start the C# service in a PowerShell Window using the run command for the service in question:

myCSharpservice.exe run

When you’ve done this all the items that are normally sent to the logging facility for C# are sent to the commandline/Powershell prompt instead. This allows for a faster diagnosis.

With that in mind I’ve written a few simple functions to test to see if the service in question has topshelf.dll included as part of its setup.  I’m using a simple routine to find out if the Dll is included in the same folder as the executable in question.

To find out what modules an EXE loads the best thing I’ve found to do this that exists in the community is through use of @mattifestation Powershell Module PowerShellArsenal.  I’m still exploring the use of his module to find the right function to see if topshelf.dll included as part of an EXE. I’ll include how to detect this with his modules in another article.

Now on to the code I wrote to do the check if the topshelf.dll  is present.

I chose to call my function to test for the existence of the topshelf.dll as Test-TopShelf

The function expects a path to an Executable.  Then from there I check to see if topshelf.dll is in the subfolder with the EXE file.  If it is I pass a True back from the function if Not I pass a false function is below:


function Test-Topshelf
{
param([string]$path)
$dllname = 'topshelf.dll'
$topshelf = $false
if (test-path -Path $path -PathType Container)
{
Push-Location
Set-Location $path
if(get-childitem -name $dllname)
{
$topshelf = $true
}
Pop-Location
else
{
Push-Location
Set-Location (get-item $path).DirectoryName
if(get-childitem -name $dllname)
{
$topshelf = $true
}
Pop-Location
}
$topshelf

}

Now all i need to do is to write a function for installing and uninstalling the EXE. Install-Service follows below:


function Install-Service
{
param
(
[string]$servicename,
[string]$username,
[string]$password,
[string]$path
)
#check to see if service includes topshelf.
if(Test-TopShelf $path)
{
Start-Process $path -ArgumentList "install -username:$username -password:$password"
#PS D:\myService\Services\csharpService> .\csharpService.exe install -username:mydomain\myServiceaccount -password:SerivcePassword
}
else
{
Write-Output "Did not detect a topshelf.dll in the directory $path is in"
}
}

Uninstall Service:


function Uninstall-Service
{
param
(
[string]$servicename,
[string]$path
)
#check to see if service includes topshelf.
if(Test-TopShelf $path)
{
Start-Process $path -ArgumentList " uninstall"
#PS D:\myService\Services\csharpService> .\csharpService.exe uninstall
}
else
{
Write-Output "Did not detect a topshelf.dll in the directory $path is in"
}
}

Now to start and stop and or detect whether or not the service is installed I use the following functions:


function Stop-TopShelfService{
param(
[string[]] $servers,
[string[]] $svcNames
)
foreach($s in $servers)
{
foreach($v in $svcNames)
{
if((get-svcinstalled -name $v -ComputerName $s).installed -eq $true)
{
Stop-Service -inputobject (Get-Service -Name $v -ComputerName $s)
}
}
}
}


function Start-TopShelfService{
param(
[string[]] $servers,
[string[]] $svcNames
)
foreach($s in $servers)
{
foreach($v in $svcNames)
{
if((get-svcinstalled -name $v -ComputerName $s).installed -eq $true)
{
Start-Service -inputobject (Get-Service -Name $v -ComputerName $s)
}
}
}
}
function Get-SvcInstalled
{
[CmdletBinding()]
param(
[parameter(ValueFromPipelineByPropertyName=$true)]
[validatenotnullorempty()]
[string[]]
[Alias('Name')]
$servicename,
[parameter(ValueFromPipelineByPropertyName=$true)]
[string[]]
[Alias('ServerName','Server','MachineName')]
$ComputerName)
Begin
{
if(!($processedServices))
{ $processedServices = @()}
}
Process
{
#write-host $servicename
if($ComputerName -eq $null)
{
$ComputerName = $env:COMPUTERNAME
}
$s = Get-service $servicename -ComputerName $ComputerName -ErrorAction SilentlyContinue
if($s)
{ $returnval = $true}
else
{$returnval = $false}
$processedServices += new-object psobject -Property (@{'serviceName' = $servicename;'installed' = $returnval;'ComputerName' = $ComputerName})
}
End
{
$processedServices
}
}

Until then keep scripting.

 

Advertisements

One thought on “Using Powershell and TopShelf to install your C# service

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s