Manually monitoring, multiple SQL Servers service & database availability, might become very challenging. Not for our SQL Super-Girl , Işıl Efe! Let’s join her and understand how she leverages PowerShell to acomplish this complex task.
If you have only one SQL Server, things are quite straightforward in terms of monitoring the status of services and databases. However, if you have multiple SQL servers, I am sure you don’t want to spend several hours going one by one to each server. In order to make things easier, I have created a PowerShell script that will help us with multiple SQL Server environments. This script will monitor:
We will create this demo on SQL 2012 SP1 running on Windows 8.1. As a prerequisite, we have to set PowerShell execution policy to RemoteSigned with the script: Set-ExecutionPolicy RemoteSigned
Now, it is time to write the PowerShell script.
We will write the code in 3 basic parts, the first part of the code is a function which gets all SQL instances from a server. The second part of the code will monitor SQL services and the last part will monitor the databases for all servers.
#Here is the first part of the code, referring PowerShell magazine here:
#http://www.powershellmagazine.com/2013/08/06/pstip-retrieve-all-sql-instance-names-on-local-and-remote-computers
#I will use this function in the 3rd part of the code to access the SQL instances to be able to check database status.
FunctionGet-SQLInstance {
param (
[string]$ComputerName=$env:COMPUTERNAME,
[string]$InstanceName
)
try {
$reg=[Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine',$ComputerName)
$regKey=$reg.OpenSubKey("SOFTWARE\\Microsoft\\Microsoft SQL Server\\Instance Names\\SQL" )
$instances=$regkey.GetValueNames()
if ($InstanceName) {
if ($instances-contains$InstanceName) {
return$true
} else {
return$false
}
} else {
$instances
}
}
catch {
Write-Error$_.Exception.Message
return$false
}
}
#I am getting the list of all SQL Servers with the following code:
$servers=@(get-content"C:\control_scripts\AllServers.txt"-TotalCount2)
#The code below is doing nothing but just defining columns of the output table:
$SrvcName =@{label="Service Name" ;alignment="left" ;width=20 ;Expression={$_.Name};};
$SrvcMode =@{label="Start Mode" ;alignment="left" ;width=20 ;Expression={$_.StartMode};};
$SrvcState =@{label="State" ;alignment="left" ;width=20 ;Expression={$_.State};};
$SrvcMsg =@{label="Message" ;alignment="left" ;width=30 ; `
Expression={if ($_.State -ne"Running") {"Alarm: Stopped"} else {"OK"} };};
`
#Here is what I am doing the basic job, With the help of Get-WmiObjectcmdlet I am getting the status information of
#SQL Server services and SQL Agent services. And with a simple for loop, I am getting start mode, state and status information.
foreach($serverin$servers)
{
$srvc=Get-WmiObject `
-query"SELECT *
FROM win32_service
WHERE name LIKE '%MSSQL%'
OR name LIKE '%SQLAgent%'" `
-computername$server `
|Sort-Object-propertyname;
Write-Output ("Server: {0}"-f$server);
Write-Output$srvc|Format-Table$SrvcName,$SrvcMode,$SrvcState,$SrvcMsg;
}
#Here is the last part of the code, the outer loop is for all servers, and the inner one is for all instances.
foreach($serverin$servers)
{
$insts=Get-SQLInstance-ComputerName$server
foreach($instin$insts)
{
#customizing the result of the function here
$sqlinst=if ($inst-eq"MSSQLSERVER") {"$server"} else {"$server\$inst"};
#T-SQL code checks the status of DBs, if all is ONLINE; then it returns OK; #if not it lists the offline DBs
$q="declare @offline table
(instnamevarchar(20),
dbnamesysname,
statusvarchar(20))
declare @query varchar(max)
declare @all int
select @all = count(name) from sys.databases
--select @all
declare @online int
select @online = count(name) from sys.databases where state=0
--select @online
if ( @online = @all)
begin
set @query='select @@servername as instname, ''all DBs'' as dbname, ''OK'' as status '
insert into @offline
exec (@query)
selectgetdate() as datetime, * from @offline
end
else
begin
set @query = 'select @@servername as instname, name as db_name, state_desc from sys.databases where state<>0'
insert into @offline
exec (@query)
selectgetdate() as datetime, * from @offline
end"
#Invoke-SQLcmdcmdlet is used to run a query on a SQL instance within #Powershell.
Invoke-Sqlcmd-ServerInstance$sqlinst-Database"master"-Query$q `
}
}
powershell.exe "C:\control_scripts\status.ps1" -noclobber >status.txt 2> status_error.txt
The successful result will be written to status.txt file as shown below.
If there are any errors, the output will be written to status_error.txt file.
Original content from Işıl Efe. Posted by MEAGBS editor Turgay Sahtiyan.