Skip to content

Instantly share code, notes, and snippets.

@Cauterite
Created April 28, 2017 06:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Cauterite/799d2e878cad64e8c306ab7e276862f9 to your computer and use it in GitHub Desktop.
Save Cauterite/799d2e878cad64e8c306ab7e276862f9 to your computer and use it in GitHub Desktop.
# ------------------------------------------------------------------------------
# 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