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?
llaravaAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Chris DentPowerShell DeveloperCommented:
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

0
Chris DentPowerShell DeveloperCommented:
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

0
llaravaAuthor Commented:
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!!
0
Defend Against the Q2 Top Security Threats

Were you aware that overall malware worldwide was down a surprising 42% from Q1'18? Every quarter, the WatchGuard Threat Lab releases an Internet Security Report that analyzes the top threat trends impacting companies worldwide. Learn more by viewing our on-demand webinar today!

llaravaAuthor Commented:
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!!
0
Chris DentPowerShell DeveloperCommented:
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

0
llaravaAuthor Commented:
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                                                     ----------????
0
Chris DentPowerShell DeveloperCommented:
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.
0
llaravaAuthor Commented:
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 ',
0
llaravaAuthor Commented:
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

0
Chris DentPowerShell DeveloperCommented:
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

0
llaravaAuthor Commented:
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!
0
Chris DentPowerShell DeveloperCommented:
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

0
llaravaAuthor Commented:
Chris - how do we control that the script will not restart the services if there are a few ping drops? Is there any contingency?
0
Chris DentPowerShell DeveloperCommented:
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

0
llaravaAuthor Commented:
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!
0
Chris DentPowerShell DeveloperCommented:
The first major section handles waiting until the share goes offline. It uses a test akin to browsing to "\\server\share" to determine if the share is up or not. A bit more detailed than Ping as it cares about the state of the thing it connects to.

In this loop "$i" tracks the number of seconds it's waiting around. "$j" tracks the number of consecutive failures.
    while ($j -le $FailAfter) {
        # Determine if the share is available (as a folder path; SMB)
        $isAvailable = Test-Path $Share
        # If the share is available, ensure the counter that triggers FailAfter is 0
        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++
        }

        # Go to sleep for the PollingFrequency value (in seconds)
        Start-Sleep -Seconds $PollingFrequency

        # Log a message every 10 minutes
        if ($i -eq 0 -or $i -ge 600) {
            # $i is 0 the very first time this runs, $i will never be 0 again at this point afterwards.
            Write-Log ('{0} is {1}' -f $Share, ('not available', 'available')[$isAvailable])
            $i = 0
        }
        # Increment i by the number of seconds between each polling attempt
        $i += $PollingFrequency
    }
    # Exit this loop when $j has reached 4 without being reset.

Open in new window

Once the share goes offline, the next piece of code triggers. This one is more complex because it includes a complex polling pattern.

In this loop "$i" has become redundant and I didn't notice until now. "$j" tracks the current position in the PollingPattern array. "$k" tracks the total number of attempts made at assessing the state of the share and is used to trigger a single admin notification (by e-mail).
    # In theory, at this point the share has gone. Wait for it to come back.
    $i = $j = $k = 0
    # The polling pattern will 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.
        # $k is never decremented, this notification will never be sent twice.
        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
        }
        # Increment k each time this loop repeats
        $k++

        # Sleep for the current value in the polling pattern.
        #   PollingPattern: 4, 2 = Sleep 4 seconds, test availability, 
        #                          sleep 2 seconds, test availability, repeat until available.
        #   PollingPattern: 10, 15, 20 = Sleep 10 seconds, test availability, sleep 15 seconds, 
        #                                test availability, sleep 20 seconds, test availability, 
        #                                repeat until available.
        Start-Sleep -Seconds $PollingPattern[$j++]
        if ($j -eq $PollingPattern.Count) {
            $j = 0
        }
    } until (Test-Path $Share)

Open in new window

The whole thing is wrapped in this loop:
while ($true) {
}

Open in new window

If a share is up, then down, then up, and the service restarted the entire process starts again (waiting for the share to drop offline).
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
llaravaAuthor Commented:
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!
0
llaravaAuthor Commented:
Also what's the expected behavior when the share goes down and becomes available after a few seconds?
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
VB Script

From novice to tech pro — start learning today.