Skip to content

Instantly share code, notes, and snippets.

@psitem
Last active March 14, 2024 20:20
Show Gist options
  • Save psitem/6ae425577496b0e4665294d88b1bfbb0 to your computer and use it in GitHub Desktop.
Save psitem/6ae425577496b0e4665294d88b1bfbb0 to your computer and use it in GitHub Desktop.
This is the Plex monitoring script that wrote and have been using since +/- 2017. I cribbed the list of processes to kill and the idea of checking that the web UI responded without error from other people's scripts but the rest is all me.
#Start-Transcript -Append -Path .\plex-monitor-transcript.log -IncludeInvocationHeader:$false -Force
<#
This is my Plex monitoring script. There are many like it, but this one is mine. If
you're running Plex as a Windows Service this script is not for you as-written, but
you could possibly modify it to work for you by commenting out the Start-Process
line, configuring the service to automatically restart, and coming up with a
different way to keep the script running.
This updated version should automatically discover the Plex installation path and
maintenance window times. If it can't, it's probably not running under the same
user account that was used to install Plex.
This version also writes to a log file. The path and name of the file will be the
same as the script, with the extention changed to .log
For my setup, the computer running Plex is configured to auto-login as 'plexuser'
and a Scheduled Task launches the script when the user logs in or connects via RDP.
General:
* Run only when user is logged on.
Triggers:
* At log on (of Plex user)
* On connection to a user session (of Plex user)
Actions:
* Start a program
* Program: powershell.exe
* Add arguments: -file [path-to]\plex-monitor.ps1
Settings:
* Allow task to be run on demand
* If the running task does not end when requested, force it to stop
* If the task is already running: Do not start a new instance
When performing a manual Plex update, stop the script. If you perform automatic updates
then they should run during the maintenance window and the script will ignore the
downtime, but I've not personally tested that scenario.
#>
function Get-PlexPath {
try {
$plexInstallFolder = Get-ItemPropertyValue -Path 'HKCU:\Software\Plex, Inc.\Plex Media Server' -name 'InstallFolder'
if ((Test-Path "$plexInstallFolder\Plex Media Server.exe") -eq $true) {
return "$plexInstallFolder\Plex Media Server.exe"
}
} catch {
# This would discover the default installation path, but that's not really wanted. If the
# registry key doesn't exist then this script is probably running as the wrong user.
#if ((Test-Path "$env:PROGRAMFILES\Plex\Plex Media Server\Plex Media Server.exe") -eq $true) {
# return "$env:PROGRAMFILES\Plex\Plex Media Server\Plex Media Server.exe"
#}
}
return $null
}
function Get-PlexMaintenanceWindow {
$ButlerStartHour = 3
$ButlerEndHour = 7
try {
$ButlerStartHour = Get-ItemPropertyValue -Path 'HKCU:\Software\Plex, Inc.\Plex Media Server' -name 'ButlerStartHour'
$ButlerEndHour = Get-ItemPropertyValue -Path 'HKCU:\Software\Plex, Inc.\Plex Media Server' -name 'ButlerEndHour'
} catch {
# Nothing
}
return "$($ButlerStartHour):00", "$($ButlerEndHour):00"
}
$PlexExePath = Get-PlexPath
$PlexUri = 'http://localhost:32400/web/index.html'
$MaintenanceStart, $MaintenanceEnd = Get-PlexMaintenanceWindow
$LogPath = (Get-Item $PSCommandPath).DirectoryName + "\" + (Get-Item $PSCommandPath).BaseName + ".log"
if ($null -eq $PlexExePath) {
"Could not locate Plex executable." | Tee-Object -FilePath $LogPath -Append
return
}
$progressPreference="SilentlyContinue"
$dt=(get-date -Format u).replace("Z", "")
"$($dt): Startup." | Tee-Object -FilePath $LogPath -Append
# Give time for system to settle / Plex to start.
Start-Sleep -Seconds 180
# Give the Maintenance Window a few minutes buffer.
$min = (Get-Date $MaintenanceStart).TimeOfDay.TotalMinutes - 2
$max = (Get-Date $MaintenanceEnd).TimeOfDay.TotalMinutes + 5
While ($true) {
try {
Invoke-WebRequest -Uri $PlexUri -TimeoutSec 30 -UseBasicParsing -DisableKeepAlive | Out-Null
} catch {
$global:ex = $_
if ($ex.Exception -like '*401*Unauthorized*') {
# This is the expected result if authentication is required.
} else {
$now = (Get-Date).TimeOfDay.TotalMinutes
if ($now -le $min -or $now -ge $max) {
$dt=(get-date -Format u).replace("Z", "")
#Write-Host "$($dt): Plex non-responsive, stopping Plex processes."
"$($dt): Plex non-responsive, stopping Plex processes." | Tee-Object -FilePath $LogPath -Append
Get-Process "Plex Media Server" -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue -PassThru | Wait-Process -Timeout 30 -ErrorAction SilentlyContinue
Get-Process "Plex Transcoder" -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue -PassThru | Wait-Process -Timeout 30 -ErrorAction SilentlyContinue
Get-Process "Plex Relay" -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue -PassThru | Wait-Process -Timeout 30 -ErrorAction SilentlyContinue
Get-Process "Plex Tuner Service" -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue -PassThru | Wait-Process -Timeout 30 -ErrorAction SilentlyContinue
Get-Process "Plex Media Scanner" -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue -PassThru | Wait-Process -Timeout 30 -ErrorAction SilentlyContinue
Get-Process "PlexScriptHost" -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue -PassThru | Wait-Process -Timeout 30 -ErrorAction SilentlyContinue
$dt=(get-date -Format u).replace("Z", "")
#Write-Host "$($dt): Starting Plex."
"$($dt): Starting Plex." | Tee-Object -FilePath $LogPath -Append
Start-Process $PlexExePath
} else {
$dt=(get-date -Format u).replace("Z", "")
#Write-Host "$($dt): Plex non-responsive during maintenance window."
"$($dt): Plex non-responsive during maintenance window." | Tee-Object -FilePath $LogPath -Append
# Sleep until maintenance window closes.
$untilSec = $max * 60 # (Get-Date $MaintenanceEnd).TimeOfDay.TotalSeconds
$nowSec = $now * 60 #(Get-Date).TimeofDay.TotalSeconds
$sleepSec = [int] ($untilSec - $nowSec)
$dt=(get-date -Format u).replace("Z", "")
#Write-Host "$($dt): Sleeping for $($sleepSec) seconds"
"$($dt): Sleeping for $($sleepSec) seconds" | Tee-Object -FilePath $LogPath -Append
Start-Sleep -Seconds $sleepSec
$dt=(get-date -Format u).replace("Z", "")
#Write-Host "$($dt): Waking."
"$($dt): Waking." | Tee-Object -FilePath $LogPath -Append
}
Start-Sleep -Seconds 60
}
}
Write-Verbose 'Sleeping.'
Start-Sleep -Seconds 5
}
#Stop-Transcript
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment