0

I'm trying to convert a .ps1 file to run as a windows service. This needs to run as a service as it's requirements for Business Continuity (scheduled task is not an option). i've always used NSSM to wrap the .ps1 as it will then run via NSSM as an exe.

This works for different scripts in Windows Server 2012, but this script is slightly different and i'm required to get this service to work on Windows Server 2016. The script itself, connects to a large amount of other servers (in total i'll have 3 services - Windows Service / Windows Process / Linux Process) which all work when just running within PowerShell.

Below is an example of the start of the script so you get an idea how it works (may not be relevant);

 while ($test = 1)
{

         [string]$query
          [string]$dbServer = "DBSERVER"   # DB Server (either IP or hostname)
          [string]$dbName   = "DBNAME" # Name of the database
          [string]$dbUser   = "CONNECTIONUSER"    # User we'll use to connect to the database/server
          [string]$dbPass   = "CONNECTIONPASSWORD"     # Password for the $dbUser


    $conn = New-Object System.Data.Odbc.OdbcConnection
    $conn.ConnectionString = "Driver={PostgreSQL Unicode(x64)};Server=$dbServer;Port=5432;Database=$dbName;Uid=$dbUser;Pwd=$dbPass;"
    $conn.open()
    $cmd = New-object System.Data.Odbc.OdbcCommand("select * from DBNAME.TABLENAME where typeofcheck = 'Windows Service' and active = 'Yes'",$conn)
    $ds = New-Object system.Data.DataSet
    (New-Object system.Data.odbc.odbcDataAdapter($cmd)).fill($ds) | out-null
    $conn.close()

$results = $ds.Tables[0]
$Output = @()

        foreach ($result in $results)
        {

            $Hostone = $Result.hostone
            $Hosttwo = $Result.hosttwo
            $Hostthree = $Result.hostthree
            $Hostfour = $Result.hostfour

        Write-Output "checking DB ID $($result.id)"

            #Host One Check
            if (!$result.hostone)
            {
            $hostonestatus = 17
            $result.hostone = ""
            }
            else
            {
            try
               {
                    if(Test-Connection -ComputerName $result.hostone -quiet -count 1)
                    {
                    $hostoneres = GET-SERVICE -COMPUTERNAME $result.hostone -NAME $result.ServiceName -ErrorAction Stop
                    $hostonestatus = $hostoneres.status.value__
                    $Result.HostOneCheckTime = "Last checked from $env:COMPUTERNAME at $(Get-date)"
                    }
                    else
                    {
                    $hostonestatus = 0
                    $result.hostonestatus = "Failed"
                    $Result.HostOneCheckTime = "Last checked from $env:COMPUTERNAME at $(Get-date)"
                    }
                }
                catch
                {
                    $hostonestatus = 0
                    $result.hostonestatus = "Failed"
                    $Result.HostOneCheckTime = "Last checked from $env:COMPUTERNAME at $(Get-date) Errors Found"
                }
                    if ($hostonestatus -eq 4)
                        {
                            $result.hostonestatus = "Running"
                        }
                    if ($hostonestatus -eq 1)
                        {
                            $result.hostonestatus = "Stopped"
                        }
                    elseif ($hostonestatus -eq 0)
                        {
                            $result.hostonestatus = "Failed"
                        }

                    }

As mentioned, the exact script running standalone works seamlessly.

Whats the best way to run this as a service or are there any known issues with NSSM when using it with Windows Server 2016?

I've also found the below which may be pointing in the right direction as i've intermittently got these in the logs;

DCOM event ID 10016 is logged in Windows

Ashaw
  • 27
  • 5
  • Running anything as a system service that wasn't written to run that way is a bad idea. If my business continuity depended on this, then I'd be tempted to re-write as a proper compiled service and run it that way. – boxdog Sep 26 '19 at 12:40

1 Answers1

1

Windows sysadmin here.

Quiet a few different ways to accomplish this from a purely service-orientated perspective.

--- 1 ---

If you are using Server 2016, I believe that the Powershell command 'New-Service' may be one of the cleanest ways. Have a look at the following for syntax and if it suits your use case --

https://support.microsoft.com/en-au/help/137890/how-to-create-a-user-defined-service

This CMDlet takes a credential parameter, so depending on your use case may be good to access resources on other foreign machines.

--- 2 ---

Another way is to use the old trusty in-built SC.exe utility in windows.

SC CREATE <servicename> Displayname= "<servicename>" binpath= "srvstart.exe <servicename> -c <path to srvstart config file>" start= <starttype>

An example --

SC CREATE Plex Displayname= "Plex" binpath= "srvstart.exe Plex -c C:PlexService.ini" start= auto

As far as I can tell, this will create a service that will execute under the Local System context. For more information, have a look at the following:

https://support.microsoft.com/en-au/help/251192/how-to-create-a-windows-service-by-using-sc-exe

https://www.howtogeek.com/50786/using-srvstart-to-run-any-application-as-a-windows-service/

--- 3 ---

You may want to consider manually injecting some registry keys to create your own service (which is essentially what SC.exe does under the hood).

Although I'm unfortunately in no position at the moment to provide boiler-plate code, I'd encourage that you have a look at the following resource:

https://www.osronline.com/article.cfm%5Eid=170.htm 

NOTE - you will need to provide all required sub-keys for it to work.

As with any registry changes, please make a backup of your registry and perform edits at your own risk prior to making any changes. I can only recommend to try this on a spare/test VM if possible prior to implementing to prod.

M2065
  • 69
  • 1
  • 7
  • i've managed to create the service without issue using the below; sc.exe create WindowsServicePoller binpath= "C:\windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -File E:\SRETools\WindowsService.ps1 –ExecutionPolicy Bypass" but the service does not start with; _Windows could not start the WindowsServicePoller service on Local Computer. Error 1053: The service did not respond to the start or control request in a timely fashion._ – Ashaw Sep 27 '19 at 10:53