NSSM 101 & Caveats

NSSM 101 & Caveats

The dreaded `Unexpected status SERVICE_PAUSED in response to START control.`

ยท

5 min read

Overview

You can use NSSM, an open-source tool with both GUI and CLI capabilities to create services on Windows. I am penning down the caveats to look out for while using NSSM.

Usage

GUI

You can create a service via GUI.

The main tabs to configure are Application and I/O.

  • Application: Configure the command to use, the directory to run from and the arguments to pass to the target command

  • I/O: To define the console input/output and error messages output files for logging

CLI

Alternatively, you can create a service via CLI.

Below is a snippet when creating a service to run a PowerShell script:

# Defining the arguments to facilitate the service creation
$powershell = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
$scriptFile = "hello-world.ps1"
$arguments = '-ExecutionPolicy Bypass -NoProfile -File {0}' -f $scriptFile

# Install the NSSM service
nssm install $serviceName $powershell $arguments 
nssm set $serviceName AppDirectory "$targetDirectory"

## Configure the standard input, output and error logs file location
nssm set $serviceName AppStdin "$stdinPath"
nssm set $serviceName AppStdout "$stdoutPath"
nssm set $serviceName AppStderr "$stderrPath"

## (Optional) Define which user to logon to run as
## Default to local system account
## Useful when you intend to use a service account to run a script/app
#nssm set $serviceName ObjectName $username $password

Caveats

When there is an error, NSSM throws an ambiguous and dreaded error message - Unexpected status SERVICE_PAUSED in response to START control. ๐Ÿ˜ฉ It is both frustrating yet interesting in the resolutions

The issues I have encountered that will result in the above error message include but are not limited to

  • NSSM misconfigurations

  • Permission issues

  • Service running too fast (?!)

  • Unable to retrieve defined global variables

NSSM misconfigurations

The issue arises due to leaving the AppError path empty. When I was new to NSSM, I interpreted that AppStdin and AppStdout would suffice the configuration.

After using NSSM for a while, I realise that it is fine to leave AppStdin or AppStdout empty, but not AppError.

This makes sense since having both AppStdin and AppStdout may mean being too verbose. However, with no AppError, the NSSM service will be unable to capture the errors thrown by the application.

Permission issues

This was a little hard to debug initially. You may need to gather context by reading into the event logs in Windows Event Viewer.

From my experience, you need to ensure that the users have the required permissions to

  • NSSM and its folder

  • Target application binary, its folder and other files

To modify the folder and file permission, right-click on the target folder > Properties > Security > Advanced.

Service running too fast

This is one of the weirdest (and mind-blowing) error I have ever encountered, whereby we are penalised for when the service is able to run quickly.

If it wasn't for this Stack Overflow post, I doubt I would be able to solve this.

To resolve this, I included Start-Sleep in my PowerShell script to make the script pauses for some time when NSSM executes it before ending the service

I suspect it might also be due to the exit method, which I set to be one-shot mode i.e. manual service. The rationale behind my perspective is:

  • NSSM is a wrapper on top of the native Windows Service Controller

  • As the one-shot mode will stop the service upon completion of execution, it can be that the underlying Windows service that NSSM interfaces with has stopped way faster than NSSM get to register the service status of START and STOP

  • Hence, resulting in the NSSM service failing to start

Unable to retrieve defined global variables

When I was running a PowerShell script that included some global variables (e.g. $global:ENV_VARIABLE), NSSM seemingly can't retrieve those values.

Some context for PowerShell session

The initial PowerShell session started will be the parent session. Using the global variables (e.g. $global:ENV_VARIABLE), the child session will be able to retrieve those values.

The rationale behind NSSM unable to retrieve global variables?

The key is - the means of invocation matters. This Stack Overflow post's example helped me to better understand PowerShell scopes.

Quoting specific sections from the PowerShell Documentation

  • From About_Scopes page

    Scripts and functions follow the rules of scope. ... When you run a script or function using dot-source notation, it runs in the current scope. Any functions, aliases, and variables in the script or function are added to the current scope.

  • From About_Operators page

    Runs a command, script, or script block. The call operator, also known as the "invocation operator", lets you run commands that are stored in variables and represented by strings or script blocks. The call operator executes in a child scope

The fact that you need to define the Application Path i.e. the path to PowerShell command, the powershell command will be invoked each time the NSSM service is started, hence a new parent session will be created with no previous global variables.

Resolution

You can leverage the AppEnvironmentExtra setting to define the global variables as environment variables (i.e. $env:ENV_VARIABLE) in the session/context managed by NSSM service.


Final Thoughts

I leveraged NSSM due to its convenience of configuring the service to logon as another Windows account. However, it can get frustrating to debug due to its generic error messages.

Considering that NSSM is not actively maintained, I am looking into the NSSM source code to better understand the underlying mechanism of the ObjectName settings and perhaps finding other means to run the application as a service on Windows.

So keep a look out for my next article! Cheers ๐Ÿป

Did you find this article valuable?

Support Bernice Choy by becoming a sponsor. Any amount is appreciated!

ย