Monitoring Critical Windows Services Across Multiple Servers with PowerShell
Today i would like to share with you one of my PowerShell script that i have created for monitoring purposes. It's a light monitoring solution that provide an easy way to monitor Windows Services across multiple Servers.
I started to create the script after receiving a request from a customer to checking several critical services for specific period of time and identify the status of them. The customer hasn't a monitoring solution and he will not provide in the future. The time it's not enough to setup a monitoring solution to get the results.
So this task should be run manual. I had to login in 10-12 different servers and manual check the status of specific services. The task it wasn't difficult but it was very time consuming.
So, instead to spend time connecting to each server every day, i decided to automate this task with a PowerShell script.
The result was to save lot of time daily, and the task was done more efficient without human errors.
In the following sections i will explain how the script works and what you need to fit in your own environment.
Prerequisites
- Enable PSRemoting to the Servers that you want to connect Remotely.
- Open the Port 5985 in your Firewall.
- Must be use administrator account for the user that you will run the script.
What the Script does
The script does the followings in order:
- If the same service included in more than one server the script use a loop to connect in multiple servers one by one.
- Connect remotely to the server.
- Do the appropriate check for the service.
- Write the status depends of the check result.
- Write the word Completed when it will finish with the check of one service to separate the checks of each service.
- Start again from the step1 to check a new Service.
How the Script Works
The script is simple without lot of complexities. The first lines includes variables with the servers that you need to connect. So you don't need to change server names in multiple places inside the code.
#Local Servers
$ws1='fqdn'
$ws2='fqdn'
$ws3='fqdn'
$ws4='fqdn'
$servers='ServerIP1','ServerIP2','ServerIP3'
Variables for server groups that will be used in ForEach
#Server groups
$usesmtps=$ws1,$db1,$db2
$websrvs=$web1,$web2,$web3
$appsrvs=$app1,$app2
The next lines include variables with the URLs, ip address that are the services that i need to check. In our case the services are an external IPs and URLs that i must get a response when i am sending the request. From your side the services might be a Windows Service or anything else.
#External URLs and Servers
$google="https://www.google.com"
$gateway='Gateway IP'
$dns= 'DNSIP1','DNSIP2','DNSIP3'
$smtp="URL or IP of an SMTP Server"
$proxy="URL or IP of a proxy"
If you should check the same service to multiple Servers use the ForEach command to login in the Servers that you will have declare in variables of Server groups.
In the following lines the script connect in each server that you have declare in the variable $websrvs and check the communication with the Test-NetConnection command in Port 443 in IP Address that you have declare in variable $gateway. The data returned by the Test-NetConnection saved to the variable $connection_status.
Inside the ScriptBlock of the Invoke-Command for each variable use the $using:<local variable> to include the local variable in a remote session. Unless when use the Invoke-Command because you are open a session to the target computer you can't see the local variable.
foreach ($websrv in $websrvrs)
{
Invoke-Command -ComputerName $websrv -ScriptBlock{
$connection_status=Test-NetConnection -ComputerName $using:gateway -Port 443 -WarningAction SilentlyContinue
The if command checks the data returned by the $connection_status in Parameter TcpTestSucceeded of the Test-NetConnection command. If the value is equal true then use the Write-Host command to print the status "Connected to <Gateway IP> in Port 443 from WebServer IP". If the value that returned isn't equal of true then Write down with Red colour "Connection failed to <Gateway IP> in Port 443 <WebServer IP> "
if ($connection_status.TcpTestSucceeded -eq "true")
{
Write-Host " Connected to $using:gateway in Port 443 from $using:$websrv" -ForegroundColor Green
}
else
{
Write-Host "Connection failed to $using:gateway in Port 443 $using:$websrv " -ForegroundColor Red
}
Lets see all the lines together that i described above
foreach ($websrv in $websrvrs)
{
Invoke-Command -ComputerName $websrv -ScriptBlock{
$connection_status=Test-NetConnection -ComputerName $using:gateway -Port 443 -WarningAction SilentlyContinue
if ($connection_status.TcpTestSucceeded -eq "true")
{
Write-Host " Connected to $using:gateway in Port 443 from $using:$websrv" -ForegroundColor Green
}
else
{
Write-Host "Connection failed to $using:gateway in Port 443 $using:$websrv " -ForegroundColor Red
}
}
}
If you have multiple services to check , it's better to separate the results for each service. So i am using the word Completed when the the service check completed. Then start with a new service check.
Write-Host ""
Write-Host " ##### Completed #####" -ForegroundColor Yellow
Write-Host ""
The next lines are checking if the google.com responding through a Proxy Server. The difference in these lines that we use the Invoke-WebRequest.
The Invoke-WebRequest has a Parametert StatusCode. If the return value of Parameter StatusCode is equal to 200 then print "Connected to Google URL in Port 443 from Server IP" else print "Connection failed to to Google URL in Port 443 from Server IP".
foreach ($server in $servers)
{
Invoke-Command -ComputerName $server -ScriptBlock{ $connection_status=Invoke- WebRequest -Uri $using:google -Proxy $using:proxy -UseBasicParsing -WarningAction SilentlyContinue
if ($connection_status.StatusCode -eq "200")
{
Write-Host " Connected to $using:google in Port 443 from $using:server" - ForegroundColor Green
}
else
{
Write-Host "Connection failed to $using:google in Port 443 $using:server " -ForegroundColor Red
}
}
}
The full script to check 2 different services is the following
#Local Servers
$ws1='fqdn'
$ws2='fqdn'
$ws3='fqdn'
$ws4='fqdn'
$servers='ServerIP1','ServerIP2','ServerIP3'
Variables for server groups that will be used in ForEach
#Server groups
$usesmtps=$ws1,$db1,$db2
$websrvs=$web1,$web2,$web3
$appsrvs=$app1,$app2
#External URLs and Servers
$google="https://www.google.com"
$gateway='Gateway IP'
$dns= 'DNSIP1','DNSIP2','DNSIP3'
$smtp="URL or IP of an SMTP Server"
$proxy="URL or IP of a proxy"
foreach ($websrv in $websrvrs)
{
Invoke-Command -ComputerName $websrv -ScriptBlock{
$connection_status=Test-NetConnection -ComputerName $using:gateway -Port 443 -WarningAction SilentlyContinue
if ($connection_status.TcpTestSucceeded -eq "true")
{
Write-Host " Connected to $using:gateway in Port 443 from $using:$websrv" -ForegroundColor Green
}
else
{
Write-Host "Connection failed to $using:gateway in Port 443 $using:$websrv " -ForegroundColor Red
}
}
}
Write-Host ""
Write-Host " ##### Completed #####" -ForegroundColor Yellow
Write-Host ""
foreach ($server in $servers)
{
Invoke-Command -ComputerName $server -ScriptBlock{ $connection_status=Invoke- WebRequest -Uri $using:google -Proxy $using:proxy -UseBasicParsing -WarningAction SilentlyContinue
if ($connection_status.StatusCode -eq "200")
{
Write-Host " Connected to $using:google in Port 443 from $using:server" - ForegroundColor Green
}
else
{
Write-Host "Connection failed to $using:google in Port 443 $using:server " -ForegroundColor Red
}
}
}
Write-Host ""
Write-Host " ##### Completed #####" -ForegroundColor Yellow
Write-Host ""
What Problems that I faced
The biggest problem that i faced regarding the infrastructure was that lot of the servers has the WSMan disabled. So i should create a GPO to enable the WSMAN instead to do it manual for each Server. However in order to GPO apply , Server must be restarted. As you know most of the times for a production environment you have a very short period time to do a Server restart.
Mu first step was to create and apply a GPO for only one Server and verify that the Server received the GPO. When i was sure that the WSMan are enable it, i applied the GPO to the other Servers.
Conclusion
Automation it's very important in our days. We can spend sometime to create a script that will automate daily tasks and reduce the time in half .
The script it has the room for improvement. You can use it in your similar tasks and do the changes base on your requirements.