Skip to content

Instantly share code, notes, and snippets.

@afscrome
Created November 28, 2016 23:26
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save afscrome/e6c4f3c8e9ca89e9882b1b77fde1e2c0 to your computer and use it in GitHub Desktop.
Save afscrome/e6c4f3c8e9ca89e9882b1b77fde1e2c0 to your computer and use it in GitHub Desktop.
Script for installing solr as a windows service
#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 { "$PSScriptRoot\nssm-x86.exe" }
$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 < nul" }
Write-Host "Updating Service MetaData" -ForegroundColor Cyan
Exec { &$nssmExe set $ServiceName DisplayName $DisplayName }
Exec { &$nssmExe set $ServiceName Description "Apache Solr (Port $Port)" }
Exec { &$nssmExe set $ServiceName AppDirectory $SolrRoot\server\tmp } # Workaround for https://issues.apache.org/jira/browse/SOLR-9760
Exec { &$nssmExe set $ServiceName AppStopMethodConsole 120000 }
Exec { &$nssmExe set $ServiceName AppExit Default Exit }
$logDir = Join-Path $SolrRoot data\logs
Exec { &$nssmExe set $ServiceName AppStdoutCreationDisposition 2 }
Exec { &$nssmExe set $ServiceName AppStderrCreationDisposition 2 }
Exec { &$nssmExe set $ServiceName AppStdout $logDir\nssm.log }
Exec { &$nssmExe set $ServiceName AppStderr $logDir\nssm.log }
#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 { sc.exe config $ServiceName obj= "$ServiceAccount" }
Write-Host "Granting file system permissions for '$ServiceAccount'" -ForegroundColor Cyan
Exec { icacls $SolrRoot /grant "${ServiceAccount}:(OI)(CI)RX" }
Exec { icacls $SolrRoot\data /grant "${ServiceAccount}:(OI)(CI)M" }
Exec { icacls $SolrRoot\server\tmp /grant "${ServiceAccount}:(OI)(CI)M" }
}
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 { &$nssmExe start $ServiceName }
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."
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment