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.
Interesting
LikeLike