- afscrome / InstallSolr.ps1
- How to Run Apache Solr as a Windows Service with AlwaysUp
- Automatically start Solr when your server boots and keep it running 24/7 in the background. Survive accidental shutdowns and other failures!
- How to create solr cloud as a windows service
- 2 Answers 2
- RobsonAutomator / pssolrservice.ps1
afscrome / InstallSolr.ps1
# Requires -Version 3.0 |
. Description |
Installs Apache Solr |
. Example |
.\ServiceInstall.ps1 |
Installs Apache Solr as the ‘solr’ service running on port 8983. |
. Example |
.\ServiceInstall.ps1 -ServiceName ‘MySearch’ -DisplayName ‘My Search’ -Port 6789 |
Installs Solr as the ‘MySearch’ service running on port 6789 |
. Parameter ServiceName |
The name to use when creating the windows service. Defaults to ‘solr’. |
Must be provided with DisplayName. |
. Parameter DisplayName |
The display name to use when creating the windows service. Defaults to ‘Solr’. |
Must be provided with ServiceName. |
. Parameter Port |
The port to run solr on. Defaults to 8983. |
#> |
param ( |
[ string ] $ServiceName = ‘ solr ‘ , |
[ string ] $DisplayName = ‘ Apache Solr ‘ , |
[ uint16 ] $Port = 8983 |
) |
# Prerequisites |
$ script :ErrorActionPreference = ‘ Stop ‘ |
if ( -not ([ Security.Principal.WindowsPrincipal ][ Security.Principal.WindowsIdentity ]::GetCurrent()).IsInRole([ Security.Principal.WindowsBuiltInRole ]::Administrator)) < |
Write-Error ‘ You must be running as an administrator to install Apache Solr ‘ |
> |
if ( Get-Service $ServiceName — ea SilentlyContinue) < |
Write-Warning » Service ‘ $ServiceName ‘ already exists. » — ErrorAction Continue |
Write-Warning » Use ServiceUninstall.ps1 to uninstall this existing instance « |
Write-Warning » If you want to run an additional instance, consider setting up new cores on the existing solr instance instead. « |
Write-Warning » Alternatively, re-run this script providing ServiceName and Port paramaters to install a new search instance. « |
return |
> |
# Helper function to validate an external command completed successfully |
function Exec < |
param ( |
[ Parameter ( Mandatory = $true )] |
[ scriptblock ] $Command |
) |
Write-Debug » Running $command « |
& $Command |
if ( $LASTEXITCODE ) < |
Write-Error » Exit Code $LASTEXITCODE whilst running $Command « |
> |
> |
$startAt = Get-Date |
try < |
$SolrRoot = Resolve-Path $PSScriptRoot \.. |
$nssmExe = if ([ Environment ]::Is64BitOperatingSystem) < " $PSScriptRoot \nssm-x64.exe " >else |
$solrCommand = Join-Path $SolrRoot bin\ solr.cmd |
$solrCommand = » «» $solrCommand «» start -port $Port -foreground -verbose -Dsolr.log.muteconsole « |
$solrCommand = $solrCommand .Replace ( ‘ » ‘ , ‘ «» ‘ ) |
When the nssm service is stopped, it issues a Ctrl+C to solr.cmd. Unfortunantly batch files have a lovely feature that |
provides a prompt to «Terminate batch job (Y/N)?». This blocks indefinitly as the service doesn’t take any standard input. |
To work around this, rather than starting solr.cmd directly, start it through cmd /C, and run solr.cmd, but redirect |
standard input from nul. This causes the prompt to be bypassed, and allows solr.cmd to exit immediatly. Thus we can now |
distinguish between solr gracefully shutting down, and solr hanging on shutdown. |
#> |
Write-Host » Installing Service » — ForegroundColor Cyan |
Exec < & $nssmExe install " $ServiceName " cmd.exe " /C $solrCommand " > |
Write-Host » Updating Service MetaData » — ForegroundColor Cyan |
Exec |
Exec |
Exec < & $nssmExe set $ServiceName AppDirectory $SolrRoot \server\tmp ># Workaround for https://issues.apache.org/jira/browse/SOLR-9760 |
Exec |
Exec |
$logDir = Join-Path $SolrRoot data \logs |
Exec |
Exec |
Exec |
Exec |
# Create needed directories |
@ ( ‘ data\logs ‘ , ‘ server\tmp ‘ ) | % < |
$fullPath = Join-Path $SolrRoot $_ |
if ( -not ( Test-Path $fullPath )) < |
New-Item $fullPath — Type Directory | out-null |
> |
> |
# Use service specific Virtual Service account to grant |
$ServiceAccount = » NT SERVICE\ $ServiceName « |
Write-Host » Configuring service to run as ‘ $ServiceAccount ‘ » — ForegroundColor Cyan |
Exec |
Write-Host » Granting file system permissions for ‘ $ServiceAccount ‘ » — ForegroundColor Cyan |
Exec < icacls $SolrRoot / grant " $ |
Exec < icacls $SolrRoot \ data / grant " $ |
Exec < icacls $SolrRoot \server\tmp / grant " $ |
> |
catch < |
if ( Get-Service $ServiceName — ea SilentlyContinue) < |
Write-Warning » Installation failed — rolling back service installation « |
& » $PSScriptRoot \ServiceUninstall.ps1 » — ServiceName $ServiceName |
> |
throw |
> |
Write-Host » Starting $ServiceName » — ForegroundColor Cyan |
try < |
Exec |
Write-Host » Solr has been successfully installed to http://localhost: $Port /solr/ » — ForegroundColor Green |
> |
catch < |
$solrLog = Join-Path $SolrRoot data \logs\solr.log |
$nssmLog = Join-Path $SolrRoot data \logs\nssm.log |
$nssmLogLastModify = ( Get-Item $nssmLog — ErrorAction SilentlyContinue).LastWriteTime |
$solrLogLastModify = ( Get-Item $solrLog — ErrorAction SilentlyContinue).LastWriteTime |
if ( $solrLogLastModify -and $solrLogLastModify -gt $nssmLogLastModify -and $solrLogLastModify -ge $startAt ) < |
$solrLogOutput = Get-Content $solrLog — Tail 10 |
if ( $solrLogOutput ) < |
Write-Host ‘ Last 10 lines of $solrLog ‘ — ForegroundColor Yellow |
$solrLogOutput |
> |
Write-Error » $ServiceName was installed, but failed to launch. Review ‘ $solrLog ‘ for more details. « |
> |
else < |
$nssmEvents = Get-EventLog — LogName Application — Source nssm — After $startAt — EntryType Error | select TimeGenerated , EntryType , Message |
if ( $nssmEvents -and $nssmLogLastModify -ge $startAt ) < |
Write-Host » Nssm errors from windows event logs » — ForegroundColor Yellow |
$nssmEvents | Format-List |
> |
else < |
$nssmLogOutput = Get-Content $nssmLog — Tail 10 |
if ( $nssmLogOutput ) |
< |
Write-Host » Last 10 lines of $nssmLog » — ForegroundColor Yellow |
$nssmLogOutput |
> |
> |
Write-Error » $ServiceName was installed, but failed to launch. Review the windows event log and ‘ $nssmLog ‘ for more details. « |
> |
> |
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
How to Run Apache Solr as a Windows Service with AlwaysUp
Automatically start Solr when your server boots and keep it running 24/7 in the background. Survive accidental shutdowns and other failures!
Apache Solr is a Java based enterprise search platform from the Apache Lucene project.
To configure Solr to start as a windows service with AlwaysUp 9.6 and later:
Download and install Solr, if necessary. We have expanded the zip file and moved its contents to C:\Solr so we will use that folder in the steps below.
Select Application > Add to open the Add Application window:
As mentioned in the Running Solr documentation, Solr can be started using the SOLR.CMD file in the bin folder. To set that up on the General tab:
In the Application field, enter the full path to your SOLR.CMD file. Since we installed Solr in C:\Solr, this is:
Be sure to use your own installation folder instead!
In the Arguments field, enter start.
In the Name field, enter the name that you will call the application in AlwaysUp. We have specified Solr but you can specify another name if you like.
Click over to the Logon tab and enter the user name and password of the Windows account in which you installed and run Solr. Solr must run in this account so that it can find its settings and environment variables (JAVA_HOME, etc.).
And while you’re here, we suggest checking the When a user logs on, don’t show the application’s windows and tray icons box at the bottom. Doing so will prevent annoying popups from the Interactive Services Detection Service as the SOLR.CMD script shows its transient windows.
Click over to the Startup tab and check the Ensure that the Windows Networking components have started box. This informs AlwaysUp that Solr needs TCP/IP networking support to do its work.
The Solr documentation recommends running the SOLR.CMD script to safely stop the server, so let’s set that up on the Extras tab:
In the Use this special command to stop the application field, enter the full command line to stop all instances of Solr. For our installation, this is:
And in the Wait for up to controls below, enter 30 seconds to give Solr extra time to stop smoothly.
We’re done configuring Solr so click the Save >> button to record your settings. In a couple of seconds, an application called Solr will show up in the AlwaysUp window. It is not yet running though, and the State column will say Stopped.
To start Solr from AlwaysUp, choose Application > Start «Solr». In a couple of seconds, the Status column will change to Running. You should be able to access Solr from your web browser now (port 8983 by default):
That’s it! Next time your computer boots, Solr will start up immediately, in the background in Session 0, without anyone needing to log on. Please restart your server now and test that Solr works as expected after Windows boots up.
And please feel free to edit Solr in AlwaysUp to check out the many other settings that may be appropriate for your environment. For example, boost Solr’s priority to give it more resources on the server, send email alerts if it stops, etc.
How to create solr cloud as a windows service
We are using solr cloud as a search service and currently we run this from command prompt of windows, but I don’t know how we can create solr cloud as a windows service on production environment.
I referred below document for the same, http://www.norconex.com/how-to-run-solr5-as-a-service-on-windows/ but it is not working as expected for solr cloud.
Can anybody please help me on this.
2 Answers 2
You need to give some information on what is not as expected .
The link shown looks like it will get you some of the way, but you obviously need to run a couple of instances, give different home locations and probably setup dependencies between the services to ensure that the one with the Zookeeper starts first. All of which you should already have by running it on the command line, so you should only need to put the corresponding parameters into corresponding fields in the GUI.
Sorry for late reply, I was on vacation.
I can run solr cloud as a windows service , but for that I need to first ccreate a complete setup of solr cloud instance using command: solr -e cloud -z localhost:2181
then need to stop all the solr port running in command prompt , by closing the command prompt.
Then I configure individual windows service for each solr port running as below:
restart -c -f -p 8984 -z 0.0.0.0:2181 -s «C:/solr-5.2.1/example/cloud/node1/solr»
and so on for every port.
This way I can configure each solr running port as a windows service.
But I want to know , is there any command in solr cloud, which will create solr cloud setup as well run all solr port under single windows service instance.
RobsonAutomator / pssolrservice.ps1
# |
# PSSolrService.ps1 |
# |
region Description |
############################################################################### |
# # |
# File name PSService.ps1 # |
# # |
# Description A sample service in a standalone PowerShell script # |
# # |
# Notes The source version of PSService.ps1 is available in GitHub# |
# repository https://github.com/JFLarvoire/SysToolsLib/ , # |
# in the PowerShell subdirectory. # |
# I remove unnecessary code and add parts regarding SOLR # |
############################################################################### |
#endregion |
#Requires -version 2 |
. SYNOPSIS |
A sample Windows service, in a standalone PowerShell script. |
. DESCRIPTION |
This script demonstrates how to write a Windows service in pure PowerShell. |
It dynamically generates a small PSService.exe wrapper, that in turn |
invokes this PowerShell script again for its start and stop events. |
. PARAMETER Start |
Start the service. |
. PARAMETER Stop |
Stop the service. |
. PARAMETER Restart |
Stop then restart the service. |
. PARAMETER Status |
Get the current service status: Not installed / Stopped / Running |
. PARAMETER Setup |
Install the service. |
. PARAMETER Remove |
Uninstall the service. |
. PARAMETER Service |
Run the service in the background. Used internally by the script. |
Do not use, except for test purposes. |
. PARAMETER Control |
Send a control message to the service thread. |
. PARAMETER Version |
Display this script version and exit. |
. EXAMPLE |
# Setup the service and run it for the first time |
C:\PS>.\PSService.ps1 -Status |
Not installed |
C:\PS>.\PSService.ps1 -Setup |
C:\PS># At this stage, a copy of PSService.ps1 is present in the path |
C:\PS>PSService -Status |
Stopped |
C:\PS>PSService -Start |
C:\PS>PSService -Status |
Running |
C:\PS># Load the log file in Notepad.exe for review |
C:\PS>notepad $ |
. EXAMPLE |
# Stop the service and uninstall it. |
C:\PS>PSService -Stop |
C:\PS>PSService -Status |
Stopped |
C:\PS>PSService -Remove |
C:\PS># At this stage, no copy of PSService.ps1 is present in the path anymore |
C:\PS>.\PSService.ps1 -Status |
Not installed |
. EXAMPLE |
# Send a control message to the service, and verify that it received it. |
C:\PS>PSService -Control Hello |
C:\PS>Notepad C:\Windows\Logs\PSService.log |
# The last lines should contain a trace of the reception of this Hello message |
#> |
[ CmdletBinding ( DefaultParameterSetName = ‘ Status ‘ )] |
Param ( |
[ Parameter ( ParameterSetName = ‘ Start ‘ , Mandatory = $true )] |
[ Switch ] $Start , # Start the service |
[ Parameter ( ParameterSetName = ‘ Stop ‘ , Mandatory = $true )] |
[ Switch ] $Stop , # Stop the service |
[ Parameter ( ParameterSetName = ‘ Restart ‘ , Mandatory = $true )] |
[ Switch ] $Restart , # Restart the service |
[ Parameter ( ParameterSetName = ‘ Status ‘ , Mandatory = $false )] |
[ Switch ] $Status = $ ( $PSCmdlet .ParameterSetName -eq ‘ Status ‘ ) , # Get the current service status |
[ Parameter ( ParameterSetName = ‘ Setup ‘ , Mandatory = $true )] |
[ Switch ] $Setup , # Install the service |
[ Parameter ( ParameterSetName = ‘ Remove ‘ , Mandatory = $true )] |
[ Switch ] $Remove , # Uninstall the service |
[ Parameter ( ParameterSetName = ‘ Service ‘ , Mandatory = $true )] |
[ Switch ] $Service , # Run the service |
[ Parameter ( ParameterSetName = ‘ Control ‘ , Mandatory = $true )] |
[ String ] $Control = $null , # Control message to send to the service |
[ Parameter ( ParameterSetName = ‘ Version ‘ , Mandatory = $true )] |
[ Switch ] $Version # Get this script version |
) |
# modify this to update script version used by Solr Service |
$scriptVersion = » 2017-11-13 « |
if ( -not ([ Security.Principal.WindowsPrincipal ] [ Security.Principal.WindowsIdentity ]::GetCurrent()).IsInRole([ Security.Principal.WindowsBuiltInRole ] » Administrator » )) |
< |
Write-Warning — Message » Please run script this with Administrator rights « |
return |
> |
# region Solr configuration |
$solrPort = ‘ 8983 ‘ |
$solrMemory = ‘ 512m ‘ # eg. 1g 4g |
$solrHome = [ environment ]::GetEnvironmentVariable( » SOLR_HOME » , [ EnvironmentVariableTarget ]::Machine) |
$solrRoot = Split-Path — Path ( Split-Path — Path $solrHome — Parent) — Parent |
$sorlStartCmd = Join-Path — Path $solrRoot — ChildPath » bin\solr.cmd « |
if ( -not ( Test-Path — Path $sorlStartCmd ) ) |
< |
Write-Warning » Solr.cmd not exist: $sorlStartCmd « |
return |
> |
# endregion |
# This script name, with various levels of details |
$argv0 = Get-Item $MyInvocation .MyCommand.Definition |
$script = $argv0 .basename # Ex: PSSolrService |
$scriptName = $argv0 .name # Ex: PSSolrService.ps1 |
$scriptFullName = $argv0 .fullname # Ex: C:\Temp\PSSolrService.ps1 |
# Global settings |
$serviceName = $script # A one-word name used for net start commands |
$serviceDisplayName = » Solr as Windows Service « |
$ServiceDescription = » Solr as Windows Service « |
$installDir = » $ < ENV: ProgramFiles>\ $serviceName » # Where to install the service files |
# $installDir = «$ |
$scriptCopy = » $installDir \ $scriptName « |
$exeName = » $serviceName .exe « |
$exeFullName = » $installDir \ $exeName « |
$logDir = » $ < ENV: windir>\Logs » # Where to log the service messages |
$logFile = » $logDir \ $serviceName .log « |
$logName = » Application » # Event Log name (Unrelated to the logFile!) |
# Note: The current implementation only supports «classic» (ie. XP-compatble) event logs. |
# To support new style (Vista and later) «Applications and Services Logs» folder trees, it would |
# be necessary to use the new *WinEvent commands instead of the XP-compatible *EventLog commands. |
# Gotcha: If you change $logName to «NEWLOGNAME», make sure that the registry key below does not exist: |
# HKLM\System\CurrentControlSet\services\eventlog\Application\NEWLOGNAME |
# Else, New-EventLog will fail, saying the log NEWLOGNAME is already registered as a source, |
# even though «Get-WinEvent -ListLog NEWLOGNAME» says this log does not exist! |
# If the -Version switch is specified, display the script version and exit. |
if ( $Version ) < |
Write-Output $scriptVersion |
return |
> |
# ——————————————————————————# |
# # |
# Function Now # |
# # |
# Description Get a string with the current time. # |
# # |
# Notes The output string is in the ISO 8601 format, except for # |
# a space instead of a T between the date and time, to # |
# improve the readability. # |
# # |
# History # |
# 2015-06-11 JFL Created this routine. # |
# # |
# ——————————————————————————# |
Function Now < |
Param ( |
[ Switch ] $ms , # Append milliseconds |
[ Switch ] $ns # Append nanoseconds |
) |
$Date = Get-Date |
$now = » « |
$now += » <0:0000>—<1:00>— <2:00>» -f $Date .Year , $Date .Month , $Date .Day |
$now += » <0:00>:<1:00>: <2:00>» -f $Date .Hour , $Date .Minute , $Date .Second |
$nsSuffix = » « |
if ( $ns ) < |
if ( » $ ( $Date .TimeOfDay ) » -match » \.\d\d\d\d\d\d » ) < |
$now += $matches [ 0 ] |
$ms = $false |
> else < |
$ms = $true |
$nsSuffix = » 000 « |
> |
> |
if ( $ms ) < |
$now += » . <0:000>$nsSuffix » -f $Date .MilliSecond |
> |
return $now |
> |
# ——————————————————————————# |
# # |
# Function Log # |
# # |
# Description Log a string into the PSService.log file # |
# # |
# Arguments A string # |
# # |
# Notes Prefixes the string with a timestamp and the user name. # |
# (Except if the string is empty: Then output a blank line.)# |
# # |
# History # |
# 2016-06-05 JFL Also prepend the Process ID. # |
# 2016-06-08 JFL Allow outputing blank lines. # |
# # |
# ——————————————————————————# |
Function Log () < |
Param ( |
[ Parameter ( Mandatory = $false , ValueFromPipeline = $true , Position = 0 )] |
[ String ] $string |
) |
if ( ! ( Test-Path $logDir )) < |
New-Item — ItemType directory — Path $logDir | Out-Null |
> |
if ( $String .length ) < |
$string = » $ ( Now ) $pid $userName $string « |
> |
$string | Out-File — Encoding ASCII — Append » $logFile « |
> |
# ——————————————————————————# |
# # |
# Function $source # |
# # |
# Description C# source of the PSService.exe stub # |
# # |
# Arguments # |
# # |
# Notes The lines commented with «SET STATUS» and «EVENT LOG» are # |
# optional. (Or blocks between «// SET STATUS [» and # |
# «// SET STATUS ]» comments.) # |
# SET STATUS lines are useful only for services with a long # |
# startup time. # |
# EVENT LOG lines are useful for debugging the service. # |
# # |
# History # |
# # |
# ——————————————————————————# |
$scriptCopyCname = $scriptCopy -replace » \\ » , » \\ » # Double backslashes. (The first \\ is a regexp with \ escaped; The second is a plain string.) |
$source = @» |
using System; |
using System.ServiceProcess; |
using System.Diagnostics; |
using System.Runtime.InteropServices; // SET STATUS |
using System.ComponentModel; // SET STATUS |
public enum ServiceType : int < // SET STATUS [ |
SERVICE_WIN32_OWN_PROCESS = 0x00000010, |
SERVICE_WIN32_SHARE_PROCESS = 0x00000020, |
>; // SET STATUS ] |
public enum ServiceState : int < // SET STATUS [ |
SERVICE_STOPPED = 0x00000001, |
SERVICE_START_PENDING = 0x00000002, |
SERVICE_STOP_PENDING = 0x00000003, |
SERVICE_RUNNING = 0x00000004, |
SERVICE_CONTINUE_PENDING = 0x00000005, |
SERVICE_PAUSE_PENDING = 0x00000006, |
SERVICE_PAUSED = 0x00000007, |
>; // SET STATUS ] |
[StructLayout(LayoutKind.Sequential)] // SET STATUS [ |
public struct ServiceStatus < |
public ServiceType dwServiceType; |
public ServiceState dwCurrentState; |
public int dwControlsAccepted; |
public int dwWin32ExitCode; |
public int dwServiceSpecificExitCode; |
public int dwCheckPoint; |
public int dwWaitHint; |
>; // SET STATUS ] |
public enum Win32Error : int < // WIN32 errors that we may need to use |
NO_ERROR = 0, |
ERROR_APP_INIT_FAILURE = 575, |
ERROR_FATAL_APP_EXIT = 713, |
ERROR_SERVICE_NOT_ACTIVE = 1062, |
ERROR_EXCEPTION_IN_SERVICE = 1064, |
ERROR_SERVICE_SPECIFIC_ERROR = 1066, |
ERROR_PROCESS_ABORTED = 1067, |
>; |
public class Service_ $serviceName : ServiceBase < // $serviceName may begin with a digit; The class name must begin with a letter |
private System.Diagnostics.EventLog eventLog; // EVENT LOG |
private ServiceStatus serviceStatus; // SET STATUS |
public Service_ $serviceName () < |
ServiceName = » $serviceName «; |
CanStop = true; |
CanPauseAndContinue = false; |
AutoLog = true; |
eventLog = new System.Diagnostics.EventLog(); // EVENT LOG [ |
if (!System.Diagnostics.EventLog.SourceExists(ServiceName)) < |
System.Diagnostics.EventLog.CreateEventSource(ServiceName, » $logName «); |
> |
eventLog.Source = ServiceName; |
eventLog.Log = » $logName «; // EVENT LOG ] |
EventLog.WriteEntry(ServiceName, » $exeName $serviceName ()»); // EVENT LOG |
> |
[DllImport(«advapi32.dll», SetLastError=true)] // SET STATUS |
private static extern bool SetServiceStatus(IntPtr handle, ref ServiceStatus serviceStatus); |
protected override void OnStart(string [] args) < |
EventLog.WriteEntry(ServiceName, » $exeName OnStart() // Entry. Starting script ‘ $scriptCopyCname ‘ -Start»); // EVENT LOG |
// Set the service state to Start Pending. // SET STATUS [ |
// Only useful if the startup time is long. Not really necessary here for a 2s startup time. |
serviceStatus.dwServiceType = ServiceType.SERVICE_WIN32_OWN_PROCESS; |
serviceStatus.dwCurrentState = ServiceState.SERVICE_START_PENDING; |
serviceStatus.dwWin32ExitCode = 0; |
serviceStatus.dwWaitHint = 2000; // It takes about 2 seconds to start PowerShell |
SetServiceStatus(ServiceHandle, ref serviceStatus); // SET STATUS ] |
// Start a child process with another copy of this script |
try < |
Process p = new Process(); |
// Redirect the output stream of the child process. |
p.StartInfo.UseShellExecute = false; |
p.StartInfo.RedirectStandardOutput = true; |
p.StartInfo.FileName = «PowerShell.exe»; |
p.StartInfo.Arguments = «-ExecutionPolicy Bypass -c & ‘ $scriptCopyCname ‘ -Start»; // Works if path has spaces, but not if it contains ‘ quotes. |
p.Start(); |
// Read the output stream first and then wait. (To avoid deadlocks says Microsoft!) |
string output = p.StandardOutput.ReadToEnd(); |
// Wait for the completion of the script startup code, that launches the -Service instance |
p.WaitForExit(); |
if (p.ExitCode != 0) throw new Win32Exception((int)(Win32Error.ERROR_APP_INIT_FAILURE)); |
// Success. Set the service state to Running. // SET STATUS |
serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING; // SET STATUS |
> catch (Exception e) < |
EventLog.WriteEntry(ServiceName, » $exeName OnStart() // Failed to start $scriptCopyCname . » + e.Message, EventLogEntryType.Error); // EVENT LOG |
// Change the service state back to Stopped. // SET STATUS [ |
serviceStatus.dwCurrentState = ServiceState.SERVICE_STOPPED; |
Win32Exception w32ex = e as Win32Exception; // Try getting the WIN32 error code |
if (w32ex == null) < // Not a Win32 exception, but maybe the inner one is. |
w32ex = e.InnerException as Win32Exception; |
> |
if (w32ex != null) < // Report the actual WIN32 error |
serviceStatus.dwWin32ExitCode = w32ex.NativeErrorCode; |
> else < // Make up a reasonable reason |
serviceStatus.dwWin32ExitCode = (int)(Win32Error.ERROR_APP_INIT_FAILURE); |
> // SET STATUS ] |
> finally < |
serviceStatus.dwWaitHint = 0; // SET STATUS |
SetServiceStatus(ServiceHandle, ref serviceStatus); // SET STATUS |
EventLog.WriteEntry(ServiceName, » $exeName OnStart() // Exit»); // EVENT LOG |
> |
> |
protected override void OnStop() < |
EventLog.WriteEntry(ServiceName, » $exeName OnStop() // Entry»); // EVENT LOG |
// Start a child process with another copy of ourselves |
Process p = new Process(); |
// Redirect the output stream of the child process. |
p.StartInfo.UseShellExecute = false; |
p.StartInfo.RedirectStandardOutput = true; |
p.StartInfo.FileName = «PowerShell.exe»; |
p.StartInfo.Arguments = «-c & ‘ $scriptCopyCname ‘ -Stop»; // Works if path has spaces, but not if it contains ‘ quotes. |
p.Start(); |
// Read the output stream first and then wait. |
string output = p.StandardOutput.ReadToEnd(); |
// Wait for the PowerShell script to be fully stopped. |
p.WaitForExit(); |
// Change the service state back to Stopped. // SET STATUS |
serviceStatus.dwCurrentState = ServiceState.SERVICE_STOPPED; // SET STATUS |
SetServiceStatus(ServiceHandle, ref serviceStatus); // SET STATUS |
EventLog.WriteEntry(ServiceName, » $exeName OnStop() // Exit»); // EVENT LOG |
> |
public static void Main() < |
System.ServiceProcess.ServiceBase.Run(new Service_ $serviceName ()); |
> |
> |
«@ |
# ——————————————————————————# |
# # |
# Function Main # |
# # |
# Description Execute the specified actions # |
# # |
# Arguments See the Param() block at the top of this script # |
# # |
# Notes # |
# # |
# History # |
# # |
# ——————————————————————————# |
# Check if we’re running as a real user, or as the SYSTEM = As a service |
$identity = [ Security.Principal.WindowsIdentity ]::GetCurrent() |
$userName = $identity .Name # Ex: «NT AUTHORITY\SYSTEM» or «Domain\Administrator» |
$authority , $name = $username -split » \\ « |
$isSystem = $identity .IsSystem # Do not test ($userName -eq «NT AUTHORITY\SYSTEM»), as this fails in non-English systems. |
# Log «# `$userName = `»$userName`» ; `$isSystem = $isSystem» |
if ( $Setup ) |
Log $MyInvocation .Line # The exact command line that was used to start us |
# The following commands write to the event log, but we need to make sure the PSService source is defined. |
New-EventLog — LogName $logName — Source $serviceName — ea SilentlyContinue |
# Workaround for PowerShell v2 bug: $PSCmdlet Not yet defined in Param() block |
$Status = ( $PSCmdlet .ParameterSetName -eq ‘ Status ‘ ) |
if ( $Start ) < # Start the service |
if ( $isSystem ) < # If running as SYSTEM, ie. invoked as a service |
# Do whatever is necessary to start the service script instance |
Log » $scriptName -Start: Starting script ‘ $scriptFullName ‘ -Service « |
Write-EventLog — LogName $logName — Source $serviceName — EventId 1001 — EntryType Information — Message » $scriptName -Start: Starting script ‘ $scriptFullName ‘ -Service « |
Start-Process PowerShell.exe — ArgumentList ( » -c & ‘ $scriptFullName ‘ -Service » ) |
> else < |
Write-Verbose » Starting service $serviceName « |
Write-EventLog — LogName $logName — Source $serviceName — EventId 1002 — EntryType Information — Message » $scriptName -Start: Starting service $serviceName « |
Start-Service $serviceName # Ask Service Control Manager to start it |
> |
return |
> |
if ( $Stop ) < # Stop the service |
if ( $isSystem ) < # If running as SYSTEM, ie. invoked as a service |
# Do whatever is necessary to stop the service script instance |
Write-EventLog — LogName $logName — Source $serviceName — EventId 1003 — EntryType Information — Message » $scriptName -Stop: Stopping script $scriptName -Service « |
Log » $scriptName -Stop: Stopping script $scriptName -Service « |
# region Solr stop |
& $sorlStartCmd stop — p $solrPort |
# endregion |
> else < |
Write-Verbose » Stopping service $serviceName « |
Write-EventLog — LogName $logName — Source $serviceName — EventId 1004 — EntryType Information — Message » $scriptName -Stop: Stopping service $serviceName « |
Stop-Service $serviceName # Ask Service Control Manager to stop it |
> |
return |
> |
if ( $Restart ) < # Restart the service |
& $scriptFullName — Stop |
& $scriptFullName — Start |
return |
> |
if ( $Status ) < # Get the current service status |
$spid = $null |
$processes = @ ( Get-WmiObject Win32_Process — filter » Name = ‘powershell.exe’ » | Where-Object < |
$_ .CommandLine -match » .* $scriptCopyCname .*-Service « |
>) |
foreach ( $process in $processes ) < # There should be just one, but be prepared for surprises. |
$spid = $process .ProcessId |
Write-Verbose » $serviceName Process >$spid « |
> |
# if (Test-Path «HKLM:\SYSTEM\CurrentControlSet\services\$serviceName») <> |
try < |
$pss = Get-Service $serviceName — ea stop # Will error-out if not installed |
> catch < |
» Not Installed « |
return |
> |
$pss .Status |
if (( $pss .Status -eq » Running » ) -and ( ! $spid )) < # This happened during the debugging phase |
Write-Error » The Service Control Manager thinks $serviceName is started, but $serviceName .ps1 -Service is not running. « |
exit 1 |
> |
return |
> |
if ( $Setup ) < # Install the service |
# Check if it’s necessary |
try < |
$pss = Get-Service $serviceName — ea stop # Will error-out if not installed |
# Check if this script is newer than the installed copy. |
if (( Get-Item $scriptCopy — ea SilentlyContinue).LastWriteTime -lt ( Get-Item $scriptFullName — ea SilentlyContinue).LastWriteTime) < |
Write-Verbose » Service $serviceName is already Installed, but requires upgrade « |
& $scriptFullName — Remove |
throw » continue « |
> else < |
Write-Verbose » Service $serviceName is already Installed, and up-to-date « |
> |
exit 0 |
> catch < |
# This is the normal case here. Do not throw or write any error! |
Write-Debug » Installation is necessary » # Also avoids a ScriptAnalyzer warning |
# And continue with the installation. |
> |
if ( ! ( Test-Path $installDir )) < |
New-Item — ItemType directory — Path $installDir | Out-Null |
> |
# Copy the service script into the installation directory |
if ( $ScriptFullName -ne $scriptCopy ) < |
Write-Verbose » Installing $scriptCopy « |
Copy-Item $ScriptFullName $scriptCopy |
> |
# Generate the service .EXE from the C# source embedded in this script |
try < |
Write-Verbose » Compiling $exeFullName « |
Add-Type — TypeDefinition $source — Language CSharp — OutputAssembly $exeFullName — OutputType ConsoleApplication — ReferencedAssemblies » System.ServiceProcess » — Debug: $false |
> catch < |
$msg = $_ .Exception.Message |
Write-error » Failed to create the $exeFullName service stub. $msg « |
exit 1 |
> |
# Register the service |
Write-Verbose » Registering service $serviceName « |
$pss = New-Service $serviceName $exeFullName — DisplayName $serviceDisplayName — Description $ServiceDescription — StartupType Automatic |
return |
> |
if ( $Remove ) < # Uninstall the service |
# Check if it’s necessary |
try < |
$pss = Get-Service $serviceName — ea stop # Will error-out if not installed |
> catch < |
Write-Verbose » Already uninstalled « |
return |
> |
Stop-Service $serviceName # Make sure it’s stopped |
# In the absence of a Remove-Service applet, use sc.exe instead. |
Write-Verbose » Removing service $serviceName « |
$msg = sc.exe delete $serviceName |
if ( $LastExitCode ) < |
Write-Error » Failed to remove the service $ |
exit 1 |
> else < |
Write-Verbose $msg |
> |
# Remove the installed files |
if ( Test-Path $installDir ) < |
foreach ( $ext in ( » exe » , » pdb » , » ps1 » )) < |
$file = » $installDir \ $serviceName . $ext « |
if ( Test-Path $file ) < |
Write-Verbose » Deleting file $file « |
Remove-Item $file |
> |
> |
if ( ! ( @ ( Get-ChildItem $installDir — ea SilentlyContinue)).Count) < |
Write-Verbose » Removing directory $installDir « |
Remove-Item $installDir |
> |
> |
return |
> |
if ( $Service ) < # Run the service |
Write-EventLog — LogName $logName — Source $serviceName — EventId 1005 — EntryType Information — Message » $scriptName -Service # Beginning background job « |
# Do the service background job |
try |
< |
# region Solr start |
Log » $scriptName Starting $sorlStartCmd with parameteres start -f -p $solrPort -m $solrMemory « |
& $sorlStartCmd start -f — p $solrPort — m $solrMemory |
# endregion |
> |
catch |
< # An exception occurred while runnning the service |
$msg = $_ .Exception.Message |
$line = $_ .InvocationInfo.ScriptLineNumber |
Log » $scriptName -Service # Error at line $ |
> |
finally |
< |
# Invoked in all cases: Exception or normally by -Stop |
# Flush all leftover events (There may be some that arrived after we exited the while event loop, but before we unregistered the events) |
$events = Get-Event | Remove-Event |
# Log a termination event, no matter what the cause is. |
Write-EventLog — LogName $logName — Source $serviceName — EventId 1006 — EntryType Information — Message » $script -Service # Exiting « |
Log » $scriptName -Service # Exiting « |
> |
return |
> |
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.