ajbs
ajbs

Reputation: 353

How to package nodejs and install a windows service with NSIS?

I am currently using os-service to create a Windows service that needs to be packaged with my Electron application. Currently, everything is installed with NSIS, but I'm not quite sure how to install and run an os-service script during installation. Likewise for uninstallation.

Anyone with experience with this? The service is installed using node to run the script.

Upvotes: 4

Views: 1926

Answers (2)

rugby2312
rugby2312

Reputation: 1484

There's a few things that the NSIS script installer will need to do:

  1. Check that the app prerequisites are installed (incl. correct nodeJS version)
  2. Install app prerequisites (NodeJS)
  3. Copy the app files to the destination folder
  4. Install the app packages (npm i)
  5. Add your app to Windows registry (so that you can find it under add/remove programs)
  6. Install node-windows library (npm i -g node-windows) to allow the app to run as a Windows service
  7. Register the app as a new windows service (remember to prepare a nodejs script https://www.npmjs.com/package/node-windows)
  8. Start your app windows service

Likewise for uninstalling you'll need to :

  1. Stop and delete the windows service linked to your app
  2. Delete your app registry keys
  3. Delete your app files and folders

Below is the script that I use for doing all the things mentioned above and more.

;!include "MUI2.nsh"

; this script will clean the folder where the application was installed
!include "UninstallLog.nsh" 

; this script is to support IF THEN
!include LogicLib.nsh


#############################################################################################
# Start
#############################################################################################

Icon "MyIcon.ico"

;miscellaneous variables
!define VERSION "1.0.0" ; app version to display on control panel
!define NAME "superapp-services-backend" ; app name to display on control panel
!define ARP "Software\Microsoft\Windows\CurrentVersion\Uninstall\${NAME}"
!define PRODUCT_PUBLISHER "dummy corp" ; app publisher to display on control panel
!define PRODUCT_URL "https://www.dummycorp.com/" ; URL to display on control panel
!define DEFAULT_DIR 'superapp-backend' ; default folder name 
!define UninstId "NSISTest" ; You might want to use a GUID here
!define MIN_NODE_MAJOR 'v18' ; minimum node Major version

; application name to show on the installer
Name "superapp service Mini Backend"

;You can remove the text 'Nullsoft Install System vX.XX' from the installer window by setting the installer attribute
BrandingText "${PRODUCT_PUBLISHER}"

;define installer name
OutFile "superapp-service-be-installer-${VERSION}.exe"

; execute as admin
RequestExecutionLevel admin

Unicode True

; set C:/ProgramFiles as default install directory
InstallDir $PROGRAMFILES64\${NAME}

; Registry key to check for directory (so if you install again, it will overwrite the old one automatically)
InstallDirRegKey HKLM "Software\${NAME}" "Install_Dir"

#############################################################################################
# Sign the installers
#############################################################################################

;sign the installer
!finalize 'ssl-certificates\dummy-ssl-certificates\signtool sign /v /f ssl-certificates\dummy-ssl-certificates\signing_keys\MySPC.pfx /fd SHA256  /t http://timestamp.digicert.com "%1"' ;= 0;

;sign the uninstaller
!uninstfinalize 'ssl-certificates\dummy-ssl-certificates\signtool sign /v /f ssl-certificates\dummy-ssl-certificates\signing_keys\MySPC.pfx /fd SHA256  /t http://timestamp.digicert.com "%1"'; = 0;

#############################################################################################
# Installer Pages
#############################################################################################

 Page components
 Page directory
 Page instfiles

 UninstPage uninstConfirm
 UninstPage instfiles

#############################################################################################
### Add Prerequsites
#############################################################################################

Section "NodeJS 18" nodev18.17.1
  ExecWait 'msiexec /i "Prerequisites\node-v18.17.1-x64.msi"'
SectionEnd 

#############################################################################################
# default section start
#############################################################################################
Section "${NAME}-${VERSION} Backend Services" Backend
  
;call UserInfo plugin to get user info.  The plugin puts the result in the stack
#UserInfo::GetAccountType 
#Pop $0 
#StrCmp $0 "Admin" +3
#   MessageBox MB_OK|MB_ICONSTOP "User must have administrative privileges to install this application"
#   Return  
  
; Check if the application is already installed
ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${NAME}" "UninstallString"
    ${If} $0 != ""
        MessageBox MB_OK|MB_ICONEXCLAMATION "${NAME} is already installed, please uninstall the current version before proceeding"
        Return
    ${EndIf}

; check node js version , abort if not installed or wrong version
nsExec::ExecToStack '"node" "--version"'
Pop $0
Pop $1

;node js is not installed
    ${If} $1 == ""
        MessageBox MB_OK|MB_ICONSTOP "Node.js version ${MIN_NODE_MAJOR} was not found. Installation will be aborted" 
        Return  
    ${EndIf}
    
; node js is installed
    ${If} $1 != "" 
    StrCpy $3 $1 3 0 ; get node js major version        
        ${If} $3 != "${MIN_NODE_MAJOR}"
            MessageBox MB_OK|MB_ICONSTOP "Found Node.js version $1Node.js ${MIN_NODE_MAJOR} is required. Installation will be aborted" 
            Return
        ${EndIf}                
    ${EndIf}
  
 
; define output path
SetOutPath $INSTDIR

; to make this item mandatory
;   SectionIn RO
  
; copy application signing and https certificates  
File /nonfatal /a /r "ssl-certificates\"

; copy node js project files
File /nonfatal /a /r "service-mynodejs-Services\" #note back slash at the end

; register signing key with powershell into local pc certificate store
ExecWait  "powershell Import-Certificate .\dummy-ssl-certificates\signing_keys\MyCA.cer -CertStoreLocation Cert:\LocalMachine\Root ; Start-Sleep -Seconds 3"

; register tls/ssl certificates with powershell into local pc certificate store
ExecWait  "powershell Import-Certificate .\dummy-ssl-certificates\https-cert\ca.pem -CertStoreLocation Cert:\LocalMachine\Root ; Start-Sleep -Seconds 3"

; install npm packages  
ExecWait 'cmd.exe /K npm i' 

; install project as a Windows service
ExecWait 'cmd.exe /K npm install -g node-windows' 
ExecWait 'cmd.exe /K node nodeService.js' 


; create a file with the application version number
FileOpen $0 "$INSTDIR\version.txt" w
 
; write the  version number to the output file
FileWrite $0 "${NAME} ${VERSION}"
 
; close the file
FileClose $0

;create shortcuts
;CreateShortcut "$DESKTOP\${NAME}.lnk" "$INSTDIR\uninstall.exe" "" "" ""
CreateDirectory "$SMPROGRAMS\${NAME}"
CreateShortcut "$SMPROGRAMS\${NAME}\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "" ""
;CreateShortcut "$SMPROGRAMS\${NAME}\Example2 (MakeNSISW).lnk" "$INSTDIR\example2.nsi" 
    
; Write the installation path into the registry
WriteRegStr HKLM SOFTWARE\${NAME} "Install_Dir" "$INSTDIR"
WriteRegStr HKLM "${ARP}" "DisplayName" "${NAME} (remove only)"
WriteRegStr HKLM "${ARP}" "Publisher" "${PRODUCT_PUBLISHER}"
WriteRegStr HKLM "${ARP}" "URLInfoAbout" "${PRODUCT_URL}"
WriteRegStr HKLM "${ARP}" "DisplayVersion" "${VERSION}"
  
; Write the uninstall keys for Windows
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${NAME}" "DisplayName" "${NAME}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${NAME}" "UninstallString" '"$INSTDIR\uninstall.exe"'
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${NAME}" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${NAME}" "NoRepair" 1
WriteUninstaller "$INSTDIR\uninstall.exe"

; start the backend service
ExecWait  "powershell Start-Service -Name mynodejsapp.exe ; Start-Sleep -Seconds 3"

;ask to reboot the pc after installing   
MessageBox MB_YESNO|MB_ICONQUESTION "Setup Complete. Do you wish to reboot the system?" IDNO +2
Reboot
   
SectionEnd

#############################################################################################
# create a section to define what the uninstaller does. the section will always be named "Uninstall"
#############################################################################################
Section "Uninstall"


; stop and delete the backend service
ExecWait  "powershell Stop-Service -Name mynodejsapp.exe ; Start-Sleep -Seconds 3 ; sc.exe delete mynodejsapp.exe ; Start-Sleep -Seconds 3 "

; Remove registry keys
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${NAME}"
DeleteRegKey HKLM SOFTWARE\${NAME}
 
; Remove shortcuts, if any
Delete "$DESKTOP\${NAME}.lnk"
 
; Delete installed file
Delete $INSTDIR\version.txt
 
; Delete the uninstaller
Delete $INSTDIR\uninstall.exe

; Remove directories and files
RMDir $SMPROGRAMS\${NAME}
!insertmacro RemoveFilesAndSubDirs "$INSTDIR"

SectionEnd

Upvotes: 0

Slappy
Slappy

Reputation: 5472

When you install Node.js runtime on target computer it should contain everything necessary to run apps properly.

Node.js also installs npm so it should be possible to execute npm install os-service from your NSIS installer somehow like this:

  1. Install Node.js runtime from your installer (it is .msi package so use ExecWait command to run it from some Temp folder)
  2. Get the npm path. Here I suppose npm on Windows is something like npm.exe located in bin or similar directory of Node.js and the path can be retrieved from Registry.
  3. Run the npm: npm install os-service from your installer - again use ExecWait or related. You will have to use absolute paths and so on.

I have no experience with web apps, there more be some dependencies and so on so you need to do a little more investigation.

Upvotes: 1

Related Questions