Discussion:
[Xymon] PS client enhancement of ServiceCheck
Timothy Williams
2018-10-08 16:05:59 UTC
Permalink
All, I've started using the servicecheck function to restart services more
extensively lately. However, I encountered a department which needs to shut
down a monitored service during a maintenance window, and the servicecheck
would restart it. Thus, I created a 'noservicecheck' item in the
client-local.cfg process. Hope you find it useful enough to add to next PS
version.

Tim Williams
Virginia Commonwealth University Computing Center

Here is a section to add to the XymonPSClient.doc help file:
noservicecheck

noservicecheck:SERVICENAME:DAYOFWEEK:STARTHOUR:DURATION

Checks if a specified Windows Service servicecheck exists and suppresses it
during the specified Maintenance Window. Window can span multiple days, as
specified by Duration, but would terminate if script is restarted after
initiation day/hour.

SERVICENAME – name of the service to check for a ‘servicecheck’ statement.

DAYOFWEEK – numeric day of the week, where Sunday = 0, Monday = 1, etc.

STARTHOUR – military hour to start the Maintenance Window, 0 for midnight
up to 23

DURATION – how long in hours a servicecheck should not institute a restart

Examples:

servicecheck:Sophos Message Router:10

noservicecheck:Sophos Message Router:0:5:1

(no restart starting first scan after Sunday 5AM to first scan after 6AM)
*Here are the revisions in XymonClient.PS1:*

*Add* following to declared variables about line 48:
$MaintChecks = @{}

*Add* line to function XymonClientConfig($cfglines) for new item to be
recognized:
-or $l -match '^noservicecheck:' `

*Replace* 'servicecheck' function:

function XymonServiceCheck
{
WriteLog "Executing XymonServiceCheck"
if ($script:clientlocalcfg_entries -ne $null)
{
$servicecfgs = @($script:clientlocalcfg_entries.keys | where { $_
-match '^servicecheck' })
foreach ($service in $servicecfgs)
{
# parameter should be
'servicecheck:<servicename>:<duration>'
$checkparams = $service -split ':'
# validation
if ($checkparams.length -ne 3)
{
WriteLog "ERROR: not enough parameters (should be
servicecheck:<servicename>:<duration>) - $checkparams[1]"
continue
}
else
{
$duration = $checkparams[2] -as [int]
if ($checkparams[1] -eq '' -or $duration -eq $null)
{
WriteLog "ERROR: config error (should be
servicecheck:<servicename>:<duration>) - $checkparams[1]"
continue
}
}
# check for maintenance window
$serviceexclds = @($script:clientlocalcfg_entries.keys |
where { $_ -match '^noservicecheck' })
foreach ($maintservice in $serviceexclds)
{
# parameter should be
'noservicecheck:<servicename>:<numeric day of week Sun=0>:<military start
hour>:<duration in Hours>'
$checkMparams = $maintservice -split ':'
if ($checkparams[1] -eq $checkMparams[1]){
# validation of number of parameters
if ($checkMparams.length -ne 5)
{
WriteLog ("ERROR: not enough parameters
(noservicecheck:<servicename>:<numeric day of week Sun=0>:<military start
hour>:<duration Hrs> {0}" -f $checkMparams[1])
continue
}
else
{
# get values
$MaintDay = $checkMparams[2] -as [int]
if($MaintDay -eq 0){$MaintWeekDay = "Sunday"}
if($MaintDay -eq 1){$MaintWeekDay = "Monday"}
if($MaintDay -eq 2){$MaintWeekDay = "Tuesday"}
if($MaintDay -eq 3){$MaintWeekDay = "Wednesday"}
if($MaintDay -eq 4){$MaintWeekDay = "Thursday"}
if($MaintDay -eq 5){$MaintWeekDay = "Friday"}
if($MaintDay -eq 6){$MaintWeekDay = "Saturday"}
$MaintStartHour = $checkMparams[3] -as [int]
$MaintDuration = $checkMparams[4] -as [int]
# validation of basic values
if ($checkMparams[1] -eq '' -or $MaintDuration -eq
$null -or ($MaintDay -inotin 0..6) -or ($MaintStartHour -inotin 0..23))
{
WriteLog ("ERROR: config error
(noservicecheck:<servicename>:<numeric day of week Sun=0>:<military start
hour>:<duration Hrs>) {0}" -f $checkMparams[1])
continue
}
}

if (((get-date).DayofWeek -eq $MaintWeekDay) -and
((get-date).Hour -eq $MaintStartHour) ) {
if
($script:MaintChecks.ContainsKey($checkMparams[1])) {
$MaintWindowEnd =
$script:MaintChecks[$checkMparams[1]].AddHours($MaintDuration)
if ((get-date) -lt $MaintWindowEnd){
WriteLog (" Maintenance: Skipping
Service Check until after $($MaintWindowEnd) for {0}" -f $checkMparams[1])
continue
}Else{
clear.variable $script:MaintChecks
}
}
else{
WriteLog ("Not seen this NoServiceCheck
before, starting Maintenance Window now for {0}" -f $checkMparams[1])
$hourTop = (get-date).Minute
$script:MaintChecks[$checkMparams[1]] =
(get-date).AddMinutes(-($hourTop))
continue
}
}
# end of maintenance hold
}
WriteLog ("Checking service {0}" -f $checkparams[1])

$winsrv = Get-Service -Name $checkparams[1]
if ($winsrv.Status -eq 'Stopped')
{
writeLog ("!! Service {0} is stopped" -f
$checkparams[1])
if ($script:ServiceChecks.ContainsKey($checkparams[1]))
{
$restarttime =
$script:ServiceChecks[$checkparams[1]].AddSeconds($duration)
writeLog "Seen this service before; restart time is
$restarttime"
if ($restarttime -lt (get-date))
{
writeLog (" -> Starting service {0}" -f
$checkparams[1])
$winsrv.Start()
}
}
else
{
writeLog "Not seen this service before, setting
restart time -1 hour"
$script:ServiceChecks[$checkparams[1]] =
(get-date).AddHours(-1)
}
}
elseif ('StartPending', 'Running' -contains $winsrv.Status)
{
writeLog " -Service is running, updating last seen
time"
$script:ServiceChecks[$checkparams[1]] = get-date
}
}
}
}
}
Beck, Zak
2018-10-09 08:06:18 UTC
Permalink
Hi Tim

I’m happy to accept this, I need to do a release soon anyway


One thing I’d really like to change, sorry it’s pernickety, is

if($MaintDay -eq 0){$MaintWeekDay = "Sunday"}
if($MaintDay -eq 1){$MaintWeekDay = "Monday"}



I’d like to replace it with:
$days = ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday')
$MaintWeekDay = $days[$MaintDay]

And move the validation before the above.

Thanks

Zak

From: Xymon <xymon-***@xymon.com> On Behalf Of Timothy Williams
Sent: Monday, 8 October 2018 17:06
To: ***@xymon.com
Subject: [External] [Xymon] PS client enhancement of ServiceCheck

All, I've started using the servicecheck function to restart services more extensively lately. However, I encountered a department which needs to shut down a monitored service during a maintenance window, and the servicecheck would restart it. Thus, I created a 'noservicecheck' item in the client-local.cfg process. Hope you find it useful enough to add to next PS version.

Tim Williams
Virginia Commonwealth University Computing Center

Here is a section to add to the XymonPSClient.doc help file:
noservicecheck
noservicecheck:SERVICENAME:DAYOFWEEK:STARTHOUR:DURATION
Checks if a specified Windows Service servicecheck exists and suppresses it during the specified Maintenance Window. Window can span multiple days, as specified by Duration, but would terminate if script is restarted after initiation day/hour.
SERVICENAME – name of the service to check for a ‘servicecheck’ statement.
DAYOFWEEK – numeric day of the week, where Sunday = 0, Monday = 1, etc.
STARTHOUR – military hour to start the Maintenance Window, 0 for midnight up to 23
DURATION – how long in hours a servicecheck should not institute a restart
Examples:
servicecheck:Sophos Message Router:10
noservicecheck:Sophos Message Router:0:5:1
(no restart starting first scan after Sunday 5AM to first scan after 6AM)
Here are the revisions in XymonClient.PS1:

Add following to declared variables about line 48:
$MaintChecks = @{}

Add line to function XymonClientConfig($cfglines) for new item to be recognized:
-or $l -match '^noservicecheck:' `

Replace 'servicecheck' function:

function XymonServiceCheck
{
WriteLog "Executing XymonServiceCheck"
if ($script:clientlocalcfg_entries -ne $null)
{
$servicecfgs = @($script:clientlocalcfg_entries.keys | where { $_ -match '^servicecheck' })
foreach ($service in $servicecfgs)
{
# parameter should be 'servicecheck:<servicename>:<duration>'
$checkparams = $service -split ':'
# validation
if ($checkparams.length -ne 3)
{
WriteLog "ERROR: not enough parameters (should be servicecheck:<servicename>:<duration>) - $checkparams[1]"
continue
}
else
{
$duration = $checkparams[2] -as [int]
if ($checkparams[1] -eq '' -or $duration -eq $null)
{
WriteLog "ERROR: config error (should be servicecheck:<servicename>:<duration>) - $checkparams[1]"
continue
}
}
# check for maintenance window
$serviceexclds = @($script:clientlocalcfg_entries.keys | where { $_ -match '^noservicecheck' })
foreach ($maintservice in $serviceexclds)
{
# parameter should be 'noservicecheck:<servicename>:<numeric day of week Sun=0>:<military start hour>:<duration in Hours>'
$checkMparams = $maintservice -split ':'
if ($checkparams[1] -eq $checkMparams[1]){
# validation of number of parameters
if ($checkMparams.length -ne 5)
{
WriteLog ("ERROR: not enough parameters (noservicecheck:<servicename>:<numeric day of week Sun=0>:<military start hour>:<duration Hrs> {0}" -f $checkMparams[1])
continue
}
else
{
# get values
$MaintDay = $checkMparams[2] -as [int]
if($MaintDay -eq 0){$MaintWeekDay = "Sunday"}
if($MaintDay -eq 1){$MaintWeekDay = "Monday"}
if($MaintDay -eq 2){$MaintWeekDay = "Tuesday"}
if($MaintDay -eq 3){$MaintWeekDay = "Wednesday"}
if($MaintDay -eq 4){$MaintWeekDay = "Thursday"}
if($MaintDay -eq 5){$MaintWeekDay = "Friday"}
if($MaintDay -eq 6){$MaintWeekDay = "Saturday"}
$MaintStartHour = $checkMparams[3] -as [int]
$MaintDuration = $checkMparams[4] -as [int]
# validation of basic values
if ($checkMparams[1] -eq '' -or $MaintDuration -eq $null -or ($MaintDay -inotin 0..6) -or ($MaintStartHour -inotin 0..23))
{
WriteLog ("ERROR: config error (noservicecheck:<servicename>:<numeric day of week Sun=0>:<military start hour>:<duration Hrs>) {0}" -f $checkMparams[1])
continue
}
}

if (((get-date).DayofWeek -eq $MaintWeekDay) -and ((get-date).Hour -eq $MaintStartHour) ) {
if ($script:MaintChecks.ContainsKey($checkMparams[1])) {
$MaintWindowEnd = $script:MaintChecks[$checkMparams[1]].AddHours($MaintDuration)
if ((get-date) -lt $MaintWindowEnd){
WriteLog (" Maintenance: Skipping Service Check until after $($MaintWindowEnd) for {0}" -f $checkMparams[1])
continue
}Else{
clear.variable $script:MaintChecks
}
}
else{
WriteLog ("Not seen this NoServiceCheck before, starting Maintenance Window now for {0}" -f $checkMparams[1])
$hourTop = (get-date).Minute
$script:MaintChecks[$checkMparams[1]] = (get-date).AddMinutes(-($hourTop))
continue
}
}
# end of maintenance hold
}
WriteLog ("Checking service {0}" -f $checkparams[1])

$winsrv = Get-Service -Name $checkparams[1]
if ($winsrv.Status -eq 'Stopped')
{
writeLog ("!! Service {0} is stopped" -f $checkparams[1])
if ($script:ServiceChecks.ContainsKey($checkparams[1]))
{
$restarttime = $script:ServiceChecks[$checkparams[1]].AddSeconds($duration)
writeLog "Seen this service before; restart time is $restarttime"
if ($restarttime -lt (get-date))
{
writeLog (" -> Starting service {0}" -f $checkparams[1])
$winsrv.Start()
}
}
else
{
writeLog "Not seen this service before, setting restart time -1 hour"
$script:ServiceChecks[$checkparams[1]] = (get-date).AddHours(-1)
}
}
elseif ('StartPending', 'Running' -contains $winsrv.Status)
{
writeLog " -Service is running, updating last seen time"
$script:ServiceChecks[$checkparams[1]] = get-date
}
}
}
}
}



________________________________

This message is for the designated recipient only and may contain privileged, proprietary, or otherwise confidential information. If you have received it in error, please notify the sender immediately and delete the original. Any other use of the e-mail by you is prohibited. Where allowed by local law, electronic communications with Accenture and its affiliates, including e-mail and instant messaging (including content), may be scanned by our systems for the purposes of information security and assessment of internal compliance with Accenture policy. Your privacy is important to us. Accenture uses your personal data only in compliance with data protection laws. For further information on how Accenture processes your personal data, please see our privacy statement at https://www.accenture.com/us-en/privacy-policy.
______________________________________________________________________________________

www.accenture.com
Timothy Williams
2018-10-09 13:28:28 UTC
Permalink
Sounds good to me. I've only been powershell coding a year, so I'm sure
there are more elegant and efficient ways than what I've devised.
Tim
Timothy Williams
2018-10-18 16:24:10 UTC
Permalink
Zak, all

I pushed my revised script out to a few servers. Most all have upgraded
powershell, but a few 2008 & 2008R2 still have PS v2. Script will not
start, but no clear error about why. It runs fine on the '08 servers with
PS v3, v4, or v5. The ones with v2 seem to be running the script in a v1
instance. Error: Program
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe for service
XymonPSClient exited with return code 4294770688. Any way to force it to
run in v2? Or do you see anything in the new function that would choke v1?
Post by Timothy Williams
Sounds good to me. I've only been powershell coding a year, so I'm sure
there are more elegant and efficient ways than what I've devised.
Tim
Storer, Raymond
2018-10-19 15:24:11 UTC
Permalink
Tim, does starting powershell.exe with the command line parameter of "-Version 2.0" help at all?

-----Original Message-----
Date: Thu, 18 Oct 2018 12:24:10 -0400
From: Timothy Williams <***@vcu.edu>
To: ***@accenture.com
Cc: ***@xymon.com
Subject: Re: [Xymon] [External] PS client enhancement of ServiceCheck
Message-ID:
<CAMVnr4NC7B7oEMYcOd5bU_JN5b58R9pmgZpZ1mLGfb+***@mail.gmail.com>
Content-Type: text/plain; charset="utf-8"

Zak, all

I pushed my revised script out to a few servers. Most all have upgraded powershell, but a few 2008 & 2008R2 still have PS v2. Script will not start, but no clear error about why. It runs fine on the '08 servers with PS v3, v4, or v5. The ones with v2 seem to be running the script in a v1 instance. Error: Program C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe for service XymonPSClient exited with return code 4294770688. Any way to force it to run in v2? Or do you see anything in the new function that would choke v1?
Post by Timothy Williams
Sounds good to me. I've only been powershell coding a year, so I'm
sure there are more elegant and efficient ways than what I've devised.
Tim
________________________________

CONFIDENTIALITY NOTICE: This email and any attachments are for the
exclusive and confidential use of the intended recipient. If you are not
the intended recipient, please do not read, distribute or take action in
reliance upon this message. If you have received this in error, please
notify us immediately by return email and promptly delete this message
and its attachments from your computer system. We do not waive
attorney-client or work product privilege by the transmission of this
message.
Beck, Zak
2018-10-22 12:16:51 UTC
Permalink
Hi

It's your use of -inotin that is not working with Powershell v2 - v2 does not support in/notin.

The workaround is this:

(0..6 -notcontains $MaintDay) -or (0..23 -notcontains $MaintStartHour)

I have included this in the latest version but I'm testing some other updates before release.

Thanks

Zak

-----Original Message-----
From: Storer, Raymond <***@nibco.com>
Sent: Friday, 19 October 2018 16:24
To: ***@xymon.com
Cc: ***@vcu.edu; Beck, Zak <***@accenture.com>
Subject: RE: [Xymon] [External] PS client enhancement of ServiceCheck

Tim, does starting powershell.exe with the command line parameter of "-Version 2.0" help at all?

-----Original Message-----
Date: Thu, 18 Oct 2018 12:24:10 -0400
From: Timothy Williams <***@vcu.edu>
To: ***@accenture.com
Cc: ***@xymon.com
Subject: Re: [Xymon] [External] PS client enhancement of ServiceCheck
Message-ID:
<CAMVnr4NC7B7oEMYcOd5bU_JN5b58R9pmgZpZ1mLGfb+***@mail.gmail.com>
Content-Type: text/plain; charset="utf-8"

Zak, all

I pushed my revised script out to a few servers. Most all have upgraded powershell, but a few 2008 & 2008R2 still have PS v2. Script will not start, but no clear error about why. It runs fine on the '08 servers with PS v3, v4, or v5. The ones with v2 seem to be running the script in a v1 instance. Error: Program C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe for service XymonPSClient exited with return code 4294770688. Any way to force it to run in v2? Or do you see anything in the new function that would choke v1?
Post by Timothy Williams
Sounds good to me. I've only been powershell coding a year, so I'm
sure there are more elegant and efficient ways than what I've devised.
Tim
________________________________

CONFIDENTIALITY NOTICE: This email and any attachments are for the exclusive and confidential use of the intended recipient. If you are not the intended recipient, please do not read, distribute or take action in reliance upon this message. If you have received this in error, please notify us immediately by return email and promptly delete this message and its attachments from your computer system. We do not waive attorney-client or work product privilege by the transmission of this message.

________________________________

This message is for the designated recipient only and may contain privileged, proprietary, or otherwise confidential information. If you have received it in error, please notify the sender immediately and delete the original. Any other use of the e-mail by you is prohibited. Where allowed by local law, electronic communications with Accenture and its affiliates, including e-mail and instant messaging (including content), may be scanned by our systems for the purposes of information security and assessment of internal compliance with Accenture policy. Your privacy is important to us. Accenture uses your personal data only in compliance with data protection laws. For further information on how Accenture processes your personal data, please see our privacy statement at https://www.accenture.com/us-en/privacy-policy.
______________________________________________________________________________________

www.accenture.com

Loading...