Avatar of llarava
llarava
Flag for Afghanistan asked on

Need assistance with script / powershell

Hi experts,

I need some assistance with the following. I need to monitor the access to a share if the share access is lost then I need keep checking until is restored and once is restored I need to restart a few services in a windows server.

Do you have a script, powershell that you can share that will allow us to get this done?
VB ScriptScripting LanguagesPowershell

Avatar of undefined
Last Comment
llarava

8/22/2022 - Mon
Chris Dent

If the script is triggered after the share goes away you don't need the first "while" loop. The "do" loop watches for the share to become available.
$share = "\\server\share"
# Watch the share until it goes away
while (Test-Path $share) {
    # How often the state of the share will be checked.
    Start-Sleep -Seconds 10
}

# In theory, at this point the share has gone. Wait for it to come back.
do {
    Start-Sleep -Seconds 10
} until (Test-Path $share)

# Now restart services
Restart-Service someService -ComputerName someServer

Open in new window

Chris Dent

Here you go, just having a bit of fun. This will run forever and will maintain a log file (in C:\Windows\Temp) to let you know what it's up to.
param(
    # The share to monitor
    [String]$Share = "\\server\share"

    # The computer which hosts services to restart
    [String]$ComputerName = 'someServer',

    # The list of services to restart on the server defined by the ComputerName parameter.
    [String[]]$Services = ('service1', 'server2')

    # How often the share is polled, in seconds
    [Int]$PollingFrequency = 10
)

function Write-Log {
    param(
        # A message to add to the log file.
        [String]$Message,

        # Indicates the severity of the event.
        [ValidateSet('INFORMATION', 'WARNING', 'ERROR')]
        [String]$LogLevel = 'INFORMATION',

        # The delimiter for the log file.
        [String]$Delimiter = "`t",

        # The number of log entries the log file is allowed to contain.
        [Int32]$MaximumSize = 2000
    )

    begin {
        $path = Join-Path ([Environment]::GetEnvironmentVariable('TEMP', 'Machine')) 'ShareMonitor.log'
    }

    process {
        '{1}{0}{2}{0}{3}' -f $Delimiter, (Get-Date).ToString('u'), $LogLevel, $Message | Out-File $path -Append
    }

    end {
        # Truncate the log file
        Set-Content $path -Value (Get-Content $path | Select-Object -Last $MaximumSize)
    }
}

$stopwatch = New-Object System.Diagnostics.StopWatch

while ($true) {
    # Watch the share until it goes away
    $stopwatch.Reset()
    $stopwatch.Start()

    $i = 0
    while (Test-Path $Share) {
        # How often the state of the share will be checked.
        Start-Sleep -Seconds $PollingFrequency

        # Log a message every 10 minutes
        if ($i -eq 0 -or $i -ge 600) {
            Write-Log ('{0} is available' -f $Share)
            $i = 0
        }
        $i += $PollingFrequency
    }

    Write-Log ('{0} has gone offline after {1} seconds' -f $Share, $stopwatch.Elapsed.TotalSeconds) -LogLevel WARNING

    $stopwatch.Reset()
    $stopwatch.Start()

    # In theory, at this point the share has gone. Wait for it to come back.
    $i = 0
    do {
        Start-Sleep -Seconds $PollingFrequency

        if ($ -eq 0 -or $i -ge 600) {
            Write-Log ('Waiting for {0} to come online' -f $Share)
            $i = 0
        }
        $i += $PollingFrequency
    } until (Test-Path $Share)

    Write-Log ('{0} came online after {1} seconds' -f $Share, $stopwatch.Elapsed.TotalSeconds)

    # Now restart services
    try {
        Restart-Service $Services -ComputerName $ComputerName -ErrorAction Stop
    } catch {
        Write-Log ('An error occurred while restarting services: {0}' -f $_.Exception.Message) -LogLevel ERROR
    }
}

Open in new window

llarava

ASKER
Chris - Thank you, That's great!

Would it be possible to add the following logic to the code:

check 1st time - is the share down yes...
wait 15 second
is down yes
wait 15 s
is down? yes
wait 15 s
is down? yes
wait 15 s  ------------  Total wait at this point is 1 minute
Do again:
is down? yes then send an email to email@domain.com
check 1st is down yes...
wait 15 second
is down yes
wait 15
is down? yes
wait 15
is down? yes
wait 15    ---- At this point is 1 more minute waiting
 
Is still down? yes! Then restart service XYZ.

------

This appears to be the logic that needs to be implemented.

Thank you!!
Your help has saved me hundreds of hours of internet surfing.
fblack61
llarava

ASKER
sorry I forgot --  Is still down? yes! Then restart service XYZ and send a new email to email@domain.com indicating services have been restated.

Thanks again!!
Chris Dent

Here you go. I think this accounts for everything.
param(
    # The share to monitor
    [String]$Share = "\\server\share"

    # The computer which hosts services to restart
    [String]$ComputerName = 'someServer',

    # The list of services to restart on the server defined by the ComputerName parameter.
    [String[]]$Services = ('service1', 'server2')

    # How often the share is polled while up, in seconds.
    [Int]$PollingFrequency = 10,

    # The pattern used to test while the share is down, in seconds.
    [Int[]]$PollingPattern = (15, 15, 15, 15, 60),

    # Send mail notifications to (mandatory).
    [String]$To = 'email@domain.com ',

    # Send mail notifications from (mandatory).
    [String]$From,

    # The SMTP server to send the message via (mandatory).
    [String]$SmtpServer
)

function Write-Log {
    param(
        # A message to add to the log file.
        [String]$Message,

        # Indicates the severity of the event.
        [ValidateSet('INFORMATION', 'WARNING', 'ERROR')]
        [String]$LogLevel = 'INFORMATION',

        # The delimiter for the log file.
        [String]$Delimiter = "`t",

        # The number of log entries the log file is allowed to contain.
        [Int32]$MaximumSize = 2000
    )

    begin {
        $path = Join-Path ([Environment]::GetEnvironmentVariable('TEMP', 'Machine')) 'ShareMonitor.log'
    }

    process {
        '{1}{0}{2}{0}{3}' -f $Delimiter, (Get-Date).ToString('u'), $LogLevel, $Message | Out-File $path -Append
    }

    end {
        # Truncate the log file
        Set-Content $path -Value (Get-Content $path | Select-Object -Last $MaximumSize)
    }
}

$mailParams = @{
    To         = $To
    From       = $From
    SmtpServer = $SmtpServer
}

$stopwatch = New-Object System.Diagnostics.StopWatch

while ($true) {
    # Watch the share until it goes away
    $stopwatch.Reset()
    $stopwatch.Start()

    $i = 0
    while (Test-Path $Share) {
        # How often the state of the share will be checked.
        Start-Sleep -Seconds $PollingFrequency

        # Log a message every 10 minutes
        if ($i -eq 0 -or $i -ge 600) {
            Write-Log ('{0} is available' -f $Share)
            $i = 0
        }
        $i += $PollingFrequency
    }

    Write-Log ('{0} has gone offline after {1} seconds' -f $Share, $stopwatch.Elapsed.TotalSeconds) -LogLevel WARNING

    $stopwatch.Reset()
    $stopwatch.Start()

    # In theory, at this point the share has gone. Wait for it to come back.
    $i = $j = $k = 0
    # The polling pattern will repeat twice inside this loop.
    do {
        Write-Log ('Waiting for {0} to come online' -f $Share)
        # A notification will be sent once, at the end of the first iteration of the 
        # polling pattern.
        if ($k -eq $j.Count) {
            $params = @{
                Subject = 'Share not available'
                Body    = 'Still waiting for {0} to come online after {1} seconds' -f $Share, ($PollingPattern | Measure-Object -Sum).Sum
            }
            Send-MailMessage @params @mailParams
        }
        $k++

        Start-Sleep -Seconds $PollingPattern[$j++]
        if ($j -eq $PollingPattern.Count) {
            $j = 0
        }
    } until ((Test-Path $Share) -or ($k -ge $PollingPattern.Count * 2))

    # Now restart services
    try {
        Restart-Service $Services -ComputerName $ComputerName -ErrorAction Stop
        Send-MailMessage -Subject 'Service restart success' -Body ('Successfully restarted {0}' -f ($Services -join ', ')) @mailParams
    } catch {
        Write-Log ('An error occurred while restarting services: {0}' -f $_.Exception.Message) -LogLevel ERROR
        Send-MailMessage -Subject 'Service restart failed' -Body ('Failed to restart {0}: {1}' -f ($Services -join ', '), $_.Exception.Message) @mailParams
    }
}

Open in new window

llarava

ASKER
Great. I am trying to test it.

How/where? do I define the SMTP server and the FROM address?

    # Send mail notifications to (mandatory).
    [String]$To = 'myemail@domain.com ',

    # Send mail notifications from (mandatory).
    [String]$From,                                                               ----------????

    # The SMTP server to send the message via (mandatory).
    [String]$SmtpServer                                                     ----------????
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Chris Dent

As is done with $To:
[String]$From = 'Someone@domain.com',

[String]$SmtpServer = 'someserver'

Open in new window

Be a little careful with SmtpServer, all parameters except the last one must end with "," and SmtpServer is the last parameter.
llarava

ASKER
Ok so:

param(
    # The share to monitor
    [String]$Share = "\\server1\temp"

    # The computer which hosts services to restart
    [String]$ComputerName = 'server1.domain.local',

    # The list of services to restart on the server defined by the ComputerName parameter.
    [String[]$Services = ('servicename')

    # How often the share is polled while up, in seconds.
    [Int]$PollingFrequency = 10,

    # The pattern used to test while the share is down, in seconds.
    [Int[]$PollingPattern = (15, 15, 15, 15, 60),

    # Send mail notifications to (mandatory).
    [String]$To = 'email@domain.com ',

    # Send mail notifications from (mandatory).
    [String]$From = 'email2@domain.com ',

    # The SMTP server to send the message via (mandatory).
    [String]$SmtpServer = 'servername ',
llarava

ASKER
Hi Chris!

Getting the following error when I run the code below - Can you please help!

At C:\Users\lla.MT\Desktop\checker.ps1:3 char:54
+     [String]$Share = "\\vsa33.mm.me\temp"
+                                                      ~
Missing ')' in function parameter list.
At C:\Users\llara.MMCNT\Desktop\checker.ps1:25 char:1
+ )
+ ~
Unexpected token ')' in expression or statement.
At C:\Users\llarNT\Desktop\checker.ps1:6 char:29
+     [String]$ComputerName = 'LA-74C4.mm.m.m',
+                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The assignment expression is not valid. The input to an assignment operator must be an object that is able to accept
assignments, such as a variable or a property.
At C:\Users\llaCNT\Desktop\checker.ps1:12 char:30
+     [Int]$PollingFrequency = 10,
+                              ~~
The assignment expression is not valid. The input to an assignment operator must be an object that is able to accept
assignments, such as a variable or a property.
At C:\Users\llaT\Desktop\checker.ps1:15 char:31
+     [Int[]$PollingPattern = (15, 15, 15, 15, 60),
+                               ~~
The assignment expression is not valid. The input to an assignment operator must be an object that is able to accept
assignments, such as a variable or a property.
At C:\Users\llaNT\Desktop\checker.ps1:15 char:35
+     [Int[]$PollingPattern = (15, 15, 15, 15, 60),
+                                   ~~
The assignment expression is not valid. The input to an assignment operator must be an object that is able to accept
assignments, such as a variable or a property.
At C:\Users\llaNT\Desktop\checker.ps1:15 char:39
+     [Int[]$PollingPattern = (15, 15, 15, 15, 60),
+                                       ~~
The assignment expression is not valid. The input to an assignment operator must be an object that is able to accept
assignments, such as a variable or a property.
At C:\Users\llar.NT\Desktop\checker.ps1:15 char:43
+     [Int[]$PollingPattern = (15, 15, 15, 15, 60),
+                                           ~~
The assignment expression is not valid. The input to an assignment operator must be an object that is able to accept
assignments, such as a variable or a property.
At C:\Users\llarT\Desktop\checker.ps1:15 char:47
+     [Int[]$PollingPattern = (15, 15, 15, 15, 60),
+                                               ~~
The assignment expression is not valid. The input to an assignment operator must be an object that is able to accept
assignments, such as a variable or a property.
At C:\Users\llarNT\Desktop\checker.ps1:18 char:19
+     [String]$To = 'lla@cy.com ',
+                   ~~~~~~~~~~~~~~~~~~~~
The assignment expression is not valid. The input to an assignment operator must be an object that is able to accept
assignments, such as a variable or a property.
Not all parse errors were reported.  Correct the reported errors and try again.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : MissingEndParenthesisInFunctionParameterList
 

param(
    # The share to monitor
    [String]$Share = "\\vsa33.mmt.s.com\temp"

    # The computer which hosts services to restart
    [String]$ComputerName = 'LA-74C4.mmt.s.com',

    # The list of services to restart on the server defined by the ComputerName parameter.
    [String[]]$Services = ('Dnscache')

    # How often the share is polled while up, in seconds.
    [Int]$PollingFrequency = 10,

    # The pattern used to test while the share is down, in seconds.
    [Int[]]$PollingPattern = (15, 15, 15, 15, 60),

    # Send mail notifications to (mandatory).
    [String]$To = 'lla@cy.com ',

    # Send mail notifications from (mandatory).
    [String]$From = 'mds@cy.com ',

    # The SMTP server to send the message via (mandatory).
    [String]$SmtpServer = 'smtprelay@cy.com '
)

function Write-Log {
    param(
        # A message to add to the log file.
        [String]$Message,

        # Indicates the severity of the event.
        [ValidateSet('INFORMATION', 'WARNING', 'ERROR')]
        [String]$LogLevel = 'INFORMATION',

        # The delimiter for the log file.
        [String]$Delimiter = "`t",

        # The number of log entries the log file is allowed to contain.
        [Int32]$MaximumSize = 2000
    )

    begin {
        $path = Join-Path ([Environment]::GetEnvironmentVariable('TEMP', 'Machine')) 'ShareMonitor.log'
    }

    process {
        '{1}{0}{2}{0}{3}' -f $Delimiter, (Get-Date).ToString('u'), $LogLevel, $Message | Out-File $path -Append
    }

    end {
        # Truncate the log file
        Set-Content $path -Value (Get-Content $path | Select-Object -Last $MaximumSize)
    }
}

$mailParams = @{
    To         = $To
    From       = $From
    SmtpServer = $SmtpServer
}

$stopwatch = New-Object System.Diagnostics.StopWatch

while ($true) {
    # Watch the share until it goes away
    $stopwatch.Reset()
    $stopwatch.Start()

    $i = 0
    while (Test-Path $Share) {
        # How often the state of the share will be checked.
        Start-Sleep -Seconds $PollingFrequency

        # Log a message every 10 minutes
        if ($i -eq 0 -or $i -ge 600) {
            Write-Log ('{0} is available' -f $Share)
            $i = 0
        }
        $i += $PollingFrequency
    }

    Write-Log ('{0} has gone offline after {1} seconds' -f $Share, $stopwatch.Elapsed.TotalSeconds) -LogLevel WARNING

    $stopwatch.Reset()
    $stopwatch.Start()

    # In theory, at this point the share has gone. Wait for it to come back.
    $i = $j = $k = 0
    # The polling pattern will repeat twice inside this loop.
    do {
        Write-Log ('Waiting for {0} to come online' -f $Share)
        # A notification will be sent once, at the end of the first iteration of the 
        # polling pattern.
        if ($k -eq $j.Count) {
            $params = @{
                Subject = 'Share not available'
                Body    = 'Still waiting for {0} to come online after {1} seconds' -f $Share, ($PollingPattern | Measure-Object -Sum).Sum
            }
            Send-MailMessage @params @mailParams
        }
        $k++

        Start-Sleep -Seconds $PollingPattern[$j++]
        if ($j -eq $PollingPattern.Count) {
            $j = 0
        }
    } until ((Test-Path $Share) -or ($k -ge $PollingPattern.Count * 2))

    # Now restart services
    try {
        Restart-Service $Services -ComputerName $ComputerName -ErrorAction Stop
        Send-MailMessage -Subject 'Service restart success' -Body ('Successfully restarted {0}' -f ($Services -join ', ')) @mailParams
    } catch {
        Write-Log ('An error occurred while restarting services: {0}' -f $_.Exception.Message) -LogLevel ERROR
        Send-MailMessage -Subject 'Service restart failed' -Body ('Failed to restart {0}: {1}' -f ($Services -join ', '), $_.Exception.Message) @mailParams
    }
}

Open in new window

Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
Chris Dent

Missing a couple of commas.
param(
    # The share to monitor
    [String]$Share = "\\vsa33.mmt.s.com\temp",

    # The computer which hosts services to restart
    [String]$ComputerName = 'LA-74C4.mmt.s.com',

    # The list of services to restart on the server defined by the ComputerName parameter.
    [String[]]$Services = ('Dnscache'),

    # How often the share is polled while up, in seconds.
    [Int]$PollingFrequency = 10,

    # The pattern used to test while the share is down, in seconds.
    [Int[]]$PollingPattern = (15, 15, 15, 15, 60),

    # Send mail notifications to (mandatory).
    [String]$To = 'lla@cy.com ',

    # Send mail notifications from (mandatory).
    [String]$From = 'mds@cy.com ',

    # The SMTP server to send the message via (mandatory).
    [String]$SmtpServer = 'smtprelay@cy.com '
)

function Write-Log {
    param(
        # A message to add to the log file.
        [String]$Message,

        # Indicates the severity of the event.
        [ValidateSet('INFORMATION', 'WARNING', 'ERROR')]
        [String]$LogLevel = 'INFORMATION',

        # The delimiter for the log file.
        [String]$Delimiter = "`t",

        # The number of log entries the log file is allowed to contain.
        [Int32]$MaximumSize = 2000
    )

    begin {
        $path = Join-Path ([Environment]::GetEnvironmentVariable('TEMP', 'Machine')) 'ShareMonitor.log'
    }

    process {
        '{1}{0}{2}{0}{3}' -f $Delimiter, (Get-Date).ToString('u'), $LogLevel, $Message | Out-File $path -Append
    }

    end {
        # Truncate the log file
        Set-Content $path -Value (Get-Content $path | Select-Object -Last $MaximumSize)
    }
}

$mailParams = @{
    To         = $To
    From       = $From
    SmtpServer = $SmtpServer
}

$stopwatch = New-Object System.Diagnostics.StopWatch

while ($true) {
    # Watch the share until it goes away
    $stopwatch.Reset()
    $stopwatch.Start()

    $i = 0
    while (Test-Path $Share) {
        # How often the state of the share will be checked.
        Start-Sleep -Seconds $PollingFrequency

        # Log a message every 10 minutes
        if ($i -eq 0 -or $i -ge 600) {
            Write-Log ('{0} is available' -f $Share)
            $i = 0
        }
        $i += $PollingFrequency
    }

    Write-Log ('{0} has gone offline after {1} seconds' -f $Share, $stopwatch.Elapsed.TotalSeconds) -LogLevel WARNING

    $stopwatch.Reset()
    $stopwatch.Start()

    # In theory, at this point the share has gone. Wait for it to come back.
    $i = $j = $k = 0
    # The polling pattern will repeat twice inside this loop.
    do {
        Write-Log ('Waiting for {0} to come online' -f $Share)
        # A notification will be sent once, at the end of the first iteration of the 
        # polling pattern.
        if ($k -eq $j.Count) {
            $params = @{
                Subject = 'Share not available'
                Body    = 'Still waiting for {0} to come online after {1} seconds' -f $Share, ($PollingPattern | Measure-Object -Sum).Sum
            }
            Send-MailMessage @params @mailParams
        }
        $k++

        Start-Sleep -Seconds $PollingPattern[$j++]
        if ($j -eq $PollingPattern.Count) {
            $j = 0
        }
    } until ((Test-Path $Share) -or ($k -ge $PollingPattern.Count * 2))

    # Now restart services
    try {
        Restart-Service $Services -ComputerName $ComputerName -ErrorAction Stop
        Send-MailMessage -Subject 'Service restart success' -Body ('Successfully restarted {0}' -f ($Services -join ', ')) @mailParams
    } catch {
        Write-Log ('An error occurred while restarting services: {0}' -f $_.Exception.Message) -LogLevel ERROR
        Send-MailMessage -Subject 'Service restart failed' -Body ('Failed to restart {0}: {1}' -f ($Services -join ', '), $_.Exception.Message) @mailParams
    }
}

Open in new window

llarava

ASKER
Chris to handle a slightly different scenario:

How would the code for previous script needs to be changed?

Scenario:

The script will be run from within the server (schedule task)

To do:

Monitor the external share
When the share is down
Is down? Yes then check every 15 seconds if the share is still down at 60 seconds then send an email with body Share down.
Then Keep monitoring until the share is up when the share is up then restart service and send an email with share is up body.

Basically we need to know the share is down via email when its been down for 60 seconds then keep watching until it's up then trigger the service restart and send a new message to comunícate it's up.

Thank you very much!
Chris Dent

It should do that. Obviously I haven't tested it through.
param(
    # The share to monitor
    [String]$Share = "\\vsa33.mmt.s.com\temp",

    # The computer which hosts services to restart
    [String]$ComputerName = 'LA-74C4.mmt.s.com',

    # The list of services to restart on the server defined by the ComputerName parameter.
    [String[]]$Services = ('Dnscache'),

    # How often the share is polled while up, in seconds.
    [Int]$PollingFrequency = 10,

    # The pattern used to test while the share is down, in seconds.
    [Int[]]$PollingPattern = (15, 15, 15, 15, 60),

    # Send mail notifications to (mandatory).
    [String]$To = 'lla@cy.com ',

    # Send mail notifications from (mandatory).
    [String]$From = 'mds@cy.com ',

    # The SMTP server to send the message via (mandatory).
    [String]$SmtpServer = 'smtprelay@cy.com '
)

function Write-Log {
    param(
        # A message to add to the log file.
        [String]$Message,

        # Indicates the severity of the event.
        [ValidateSet('INFORMATION', 'WARNING', 'ERROR')]
        [String]$LogLevel = 'INFORMATION',

        # The delimiter for the log file.
        [String]$Delimiter = "`t",

        # The number of log entries the log file is allowed to contain.
        [Int32]$MaximumSize = 2000
    )

    begin {
        $path = Join-Path ([Environment]::GetEnvironmentVariable('TEMP', 'Machine')) 'ShareMonitor.log'
    }

    process {
        '{1}{0}{2}{0}{3}' -f $Delimiter, (Get-Date).ToString('u'), $LogLevel, $Message | Out-File $path -Append
    }

    end {
        # Truncate the log file
        Set-Content $path -Value (Get-Content $path | Select-Object -Last $MaximumSize)
    }
}

$mailParams = @{
    To         = $To
    From       = $From
    SmtpServer = $SmtpServer
}

$stopwatch = New-Object System.Diagnostics.StopWatch

while ($true) {
    # Watch the share until it goes away
    $stopwatch.Reset()
    $stopwatch.Start()

    $i = 0
    while (Test-Path $Share) {
        # How often the state of the share will be checked.
        Start-Sleep -Seconds $PollingFrequency

        # Log a message every 10 minutes
        if ($i -eq 0 -or $i -ge 600) {
            Write-Log ('{0} is available' -f $Share)
            $i = 0
        }
        $i += $PollingFrequency
    }

    Write-Log ('{0} has gone offline after {1} seconds' -f $Share, $stopwatch.Elapsed.TotalSeconds) -LogLevel WARNING

    $stopwatch.Reset()
    $stopwatch.Start()

    # In theory, at this point the share has gone. Wait for it to come back.
    $i = $j = $k = 0
    # The polling pattern will repeat twice inside this loop.
    do {
        Write-Log ('Waiting for {0} to come online' -f $Share)
        # A notification will be sent once, at the end of the first iteration of the 
        # polling pattern.
        if ($k -eq $j.Count) {
            $params = @{
                Subject = 'Share not available'
                Body    = 'Still waiting for {0} to come online after {1} seconds' -f $Share, ($PollingPattern | Measure-Object -Sum).Sum
            }
            Send-MailMessage @params @mailParams
        }
        $k++

        Start-Sleep -Seconds $PollingPattern[$j++]
        if ($j -eq $PollingPattern.Count) {
            $j = 0
        }
    } until (Test-Path $Share)

    # Now restart services
    try {
        Restart-Service $Services -ComputerName $ComputerName -ErrorAction Stop
        Send-MailMessage -Subject 'Service restart success' -Body ('Successfully restarted {0}' -f ($Services -join ', ')) @mailParams
    } catch {
        Write-Log ('An error occurred while restarting services: {0}' -f $_.Exception.Message) -LogLevel ERROR
        Send-MailMessage -Subject 'Service restart failed' -Body ('Failed to restart {0}: {1}' -f ($Services -join ', '), $_.Exception.Message) @mailParams
    }
}

Open in new window

⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
llarava

ASKER
Chris - how do we control that the script will not restart the services if there are a few ping drops? Is there any contingency?
Chris Dent

This version has a bit of failure tolerance built in. By default the test must fail 4 times in a row for the share to be considered offline.
param(
    # The share to monitor
    [String]$Share = "\\vsa33.mmt.s.com\temp",

    # The computer which hosts services to restart
    [String]$ComputerName = 'LA-74C4.mmt.s.com',

    # The list of services to restart on the server defined by the ComputerName parameter.
    [String[]]$Services = ('Dnscache'),

    # How often the share is polled while up, in seconds.
    [Int]$PollingFrequency = 10,

    # The pattern used to test while the share is down, in seconds.
    [Int[]]$PollingPattern = (15, 15, 15, 15, 60),

    # Consider a share to have failed when it is not available for more than a specific number of tests.
    [Int]$FailAfter = 4,

    # Send mail notifications to (mandatory).
    [String]$To = 'lla@cy.com',

    # Send mail notifications from (mandatory).
    [String]$From = 'mds@cy.com',

    # The SMTP server to send the message via (mandatory).
    [String]$SmtpServer = 'smtprelay@cy.com'
)

function Write-Log {
    param(
        # A message to add to the log file.
        [String]$Message,

        # Indicates the severity of the event.
        [ValidateSet('INFORMATION', 'WARNING', 'ERROR')]
        [String]$LogLevel = 'INFORMATION',

        # The delimiter for the log file.
        [String]$Delimiter = "`t",

        # The number of log entries the log file is allowed to contain.
        [Int32]$MaximumSize = 2000
    )

    begin {
        $path = Join-Path ([Environment]::GetEnvironmentVariable('TEMP', 'Machine')) 'ShareMonitor.log'
    }

    process {
        '{1}{0}{2}{0}{3}' -f $Delimiter, (Get-Date).ToString('u'), $LogLevel, $Message | Out-File $path -Append
    }

    end {
        # Truncate the log file
        Set-Content $path -Value (Get-Content $path | Select-Object -Last $MaximumSize)
    }
}

$mailParams = @{
    To         = $To
    From       = $From
    SmtpServer = $SmtpServer
}

$stopwatch = New-Object System.Diagnostics.StopWatch

while ($true) {
    # Watch the share until it goes away
    $stopwatch.Reset()
    $stopwatch.Start()

    $i = $j = 0
    while ($j -le $FailAfter) {
        $isAvailable = Test-Path $Share
        if ($isAvailable) {
            # Reset the counter j if the share is available
            $j = 0
        } else {
            # Increase the counter j if the share is not available
            $j++
        }

        # How often the state of the share will be checked.
        Start-Sleep -Seconds $PollingFrequency

        # Log a message every 10 minutes
        if ($i -eq 0 -or $i -ge 600) {
            Write-Log ('{0} is {1}' -f $Share, ('not available', 'available')[$isAvailable])
            $i = 0
        }
        $i += $PollingFrequency
    }

    Write-Log ('{0} has gone offline after {1} seconds' -f $Share, $stopwatch.Elapsed.TotalSeconds) -LogLevel WARNING

    $stopwatch.Reset()
    $stopwatch.Start()

    # In theory, at this point the share has gone. Wait for it to come back.
    $i = $j = $k = 0
    # The polling pattern will repeat twice inside this loop.
    do {
        Write-Log ('Waiting for {0} to come online' -f $Share)
        # A notification will be sent once, at the end of the first iteration of the 
        # polling pattern.
        if ($k -eq $j.Count) {
            $params = @{
                Subject = 'Share not available'
                Body    = 'Still waiting for {0} to come online after {1} seconds' -f $Share, ($PollingPattern | Measure-Object -Sum).Sum
            }
            Send-MailMessage @params @mailParams
        }
        $k++

        Start-Sleep -Seconds $PollingPattern[$j++]
        if ($j -eq $PollingPattern.Count) {
            $j = 0
        }
    } until (Test-Path $Share)

    # Now restart services
    try {
        Restart-Service $Services -ComputerName $ComputerName -ErrorAction Stop
        Send-MailMessage -Subject 'Service restart success' -Body ('Successfully restarted {0}' -f ($Services -join ', ')) @mailParams
    } catch {
        Write-Log ('An error occurred while restarting services: {0}' -f $_.Exception.Message) -LogLevel ERROR
        Send-MailMessage -Subject 'Service restart failed' -Body ('Failed to restart {0}: {1}' -f ($Services -join ', '), $_.Exception.Message) @mailParams
    }
}

Open in new window

llarava

ASKER
Hi Chris! Can you please explain a little bit the code in the counters? Also when you say fail 4 times what do you mean? I am understanding something like check every second share access until the share is down then when down check every 15 sec until you get to a minute then send an email and restart the service/email again? Could you please help me to understand a bit more the code? Also how are you checking the access to the share?

Thank you very much I really appreciate it!
This is the best money I have ever spent. I cannot not tell you how many times these folks have saved my bacon. I learn so much from the contributors.
rwheeler23
ASKER CERTIFIED SOLUTION
Chris Dent

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
llarava

ASKER
Monitor the external share
When the share is down
Is down? Yes then check every 15 seconds if the share is still down at 60 seconds then send an email with body Share down.

Is this the sequence:
 # The pattern used to test while the share is down, in seconds.
    [Int[]$PollingPattern = (15, 15, 15, 15, 60),

I received the following email when the share is down -- Still waiting for \\server\share to come online after 120 seconds

Where is the 120 seconds coming from? just trying to understand the pattern.

Can you walk me trough an example...of what's expected this will help me to better understand the code.

--Script checks every second
1.) share is up  10:10:00 AM
2.) share is down 10:10:10 AM
3.) Script finds is down and checks 10:10:15 AM - down? yes
4.) Are you still down and checks 10:10:30 AM - down? yes
5.) Are you still down and checks 10:10:45 AM - down? yes
6.) Are you still down and checks 10:10:60 AM - down? yes
7.) Send email alert --  Still waiting for \\server\share to come online after 120 seconds (why 120 seconds)
8.) Script to keep checking until the share becomes available.
9.) When available restart the service and send email.

Des that makes sense? Where does the failure tolerance kicks in?

Thanks again for your patience!
llarava

ASKER
Also what's the expected behavior when the share goes down and becomes available after a few seconds?