Created
April 28, 2017 06:37
-
-
Save Cauterite/799d2e878cad64e8c306ab7e276862f9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ------------------------------------------------------------------------------ | |
# Leopard Systems ? (2017) | |
# contributors: Adam Laing | |
# note: requires powershell 2.0 or later | |
set-strictmode -version 'latest' | |
$erroractionpreference = 'stop' | |
# ------------------------------------------------------------------------------ | |
add-type -assemblyname 'system.windows.forms' | |
add-type -assemblyname 'presentationframework' | |
add-type -assemblyname 'windowsformsintegration' | |
set-variable taskname -option constant -value 'checkhealth' | |
set-variable rootdir -option constant ` | |
-value ([io.path]::getdirectoryname($script:myinvocation.mycommand.path)) | |
$taskinfo = $null | |
function entrypoint { | |
# must run with -sta | |
enforce ([threading.thread]::currentthread.getapartmentstate() ` | |
-eq [threading.apartmentstate]::sta) | |
[windows.forms.application]::enablevisualstyles() | |
[windows.forms.application]::run((create-main-form)) | |
} | |
function create-main-form { | |
$mf = new-object windows.forms.form | |
$mf.text = 'Server Health Monitor' | |
$mf.showicon = $false | |
# status info | |
# buttons: | |
# enable/disable | |
# pause | |
# refresh | |
$xamlsrc = @' | |
<Window | |
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms" | |
> | |
<WindowsFormsHost> | |
<wf:MaskedTextBox x:Name="mtbDate" Mask="00/00/0000"/> | |
</WindowsFormsHost> | |
</Window> | |
'@ # picky syntax - no space before this token | |
# put the xaml in the form | |
$mf.controls.add( | |
[windows.markup.xamlreader]::parse($xamlsrc).content.child) | |
update-main-form $mf | |
$mf.add_shown({main-form-onshown $mf}.getnewclosure()) | |
return $mf | |
} | |
function main-form-onshown($mf) { | |
$taskinfo = $(try {checkhealth-task-info $taskname} catch { | |
throw xcep "failed to get info for task '$taskname'" $_}) | |
log "checkhealth var path: `"$($taskinfo.varpath)`"" | |
update-main-form $mf | |
pause-checkhealth-task (new-object timespan(1, 0, 0)) # 1 hour | |
} | |
function update-main-form($mf) { | |
# | |
} | |
function pause-checkhealth-task($duration) { | |
enforce ($duration -is [timespan]) | |
enforce ($duration.ticks -gt 0) | |
log "pausing task for duration: $duration ..." | |
$pauseuntil = (get-date).add($duration) | |
# write the pause details into the checkhealth var file | |
with-task-stopped $taskinfo.taskobj { | |
$vardoc = read-checkhealth-state-file $taskinfo.varpath | |
$vardoc.selectsinglenode('/*').` | |
setattribute('pause-until', "$($pauseuntil.ticks)") | |
$vardoc.save($taskinfo.varpath) | |
} | |
log '... done' | |
} | |
function with-task-stopped($taskobj, $fn) { | |
enforce ($taskobj -is [__comobject]) | |
enforce ($fn -is [scriptblock]) | |
$wasenabled = $taskobj.enabled | |
$taskobj.stop(0) | |
$taskobj.enabled = $false | |
trap {$taskobj.enabled = $wasenabled} | |
& $fn | |
$taskobj.enabled = $wasenabled | |
} | |
function read-checkhealth-state-file($path) { | |
# or create a new xml document if the file doesn't exist | |
# should only use inside a 'with-task-stopped' block | |
try { | |
if (test-path -literalpath $path -pathtype 'leaf') { | |
return slurp-xml $path | |
} else { | |
$d = new-object xml.xmldocument | |
$d.loadxml('<var/>') | |
return $d | |
} | |
} catch { | |
throw xcep "failed to read state file `"$path`"" $_ | |
} | |
} | |
function checkhealth-task-info($taskname) { | |
# find the checkhealth scheduled task and script dir | |
$s = new-object -comobject 'schedule.service' | |
$s.connect() | |
$task = enforce ( | |
$s.getfolder('\').gettasks(0) | ? {$_.name -eq $taskname}) | |
$xs = $task.definition.actions | |
[void] (enforce ($xs.count -eq 1)) | |
[void] (enforce ($xs.item(1).type -eq 0)) # TASK_ACTION_EXEC | |
$dir = [io.path]::getdirectoryname($xs.item(1).path) | |
[void] (enforce (test-path -literalpath $dir -pathtype 'container')) | |
return @{ | |
taskobj = $task; | |
scriptdir = $dir; | |
varpath = (join-path $dir 'var.xml');} | |
} | |
function slurp-xml($filepath) { | |
$cfgxml = new-object xml.xmldocument | |
$r = new-object xml.xmltextreader($filepath) | |
$cfgxml.load($r) | |
$r.close() | |
return $cfgxml | |
} | |
function log($msg) { | |
[void] (write-host -nonewline -object "$msg `r`n") | |
} | |
function enforce($cond) { | |
# [intptr]::zero is a truthy value apparently | |
# so explicit test for 0 | |
if (!$cond -or ($cond -eq 0)) { | |
throw xcep ( | |
'enforcement failed @ line {0}' -f $myinvocation.scriptlinenumber)} | |
return $cond | |
} | |
function xcep($msg, $innerx) { | |
if ($innerx -is [management.automation.errorrecord]) { | |
$innerx = $innerx.exception} | |
new-object applicationexception($msg, $innerx) | |
} | |
# ------------------------------------------------------------------------------ | |
[void] (entrypoint) | |
# ------------------------------------------------------------------------------ | |
<# | |
$(# need the task enabled to do anything | |
$s = $taskinfo.taskobj.definition.settings | |
if (!$s.enabled) { | |
$answer = [windows.forms.messagebox]::show( | |
"Task '$taskname' is disabled. Enable it now?", # message | |
'', # title | |
[windows.forms.messageboxbuttons]::yesno, | |
[windows.forms.messageboxicon]::exclamation, | |
[windows.forms.messageboxdefaultbutton]::button2, | |
0) | |
if ($answer -eq [windows.forms.dialogresult]::yes) { | |
$s.enabled = $true | |
log "task '$taskname' enabled" | |
} else { | |
log "task '$taskname' not enabled, terminating" | |
[windows.forms.application]::exit() | |
} | |
} | |
) | |
#> | |
# ------------------------------------------------------------------------------ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment