SQL Server Forums
Profile | Register | Active Topics | Members | Search | Forum FAQ
 
Register Now and get your question answered!
Username:
Password:
Save Password
Forgot your Password?

 All Forums
 General SQL Server Forums
 Script Library
 Powershell Excursions
 New Topic  Reply to Topic
 Printer Friendly
Author Previous Topic Topic Next Topic  

rockmoose
SQL Natt Alfen

Sweden
3279 Posts

Posted - 12/26/2006 :  12:18:42  Show Profile  Reply with Quote
I was just playing around with Powershell, and I must say I am very happy about that new scripting environment.
You will need to download Powershell from microsoft before you can try these examples.

My first attempt was to collect data from various WMI counters, and store these into a database.
So here follow some sample scripts that demonstrate how that can be done.
And hopefully demonstrate the power and "ease of use" of powershell.

We have the following scripts:

1. create tables & procedures (this sets up the tables (3) and sp (1) that receives the performance counter values from the ps scripts)
2. include_monitor_performanceCounterValue.ps1 (this is a ps script that is "included" in other scripts just to call the database)
3. processor.ps1 (a sample powershell script to collect processorload counters)
3. disk.ps1 (a sample powershell script to collect logical disk counters)

What these scripts do are:
a) collect processor load every 10 seconds from select computers and save this into a db table
b) collect diskqueue lenght, disk free space from select computers and save this into a db table

Some caveats I encountered:
For some machines I received an error RPC server unavailable, but if I added the machine to the hosts file, it worked.
You need to run the scripts under an account that has access to the WMI counters.

------------------------------------------------------------------------------------------------------------------------------------------------------------------

1. create tables & procedures (this sets up the tables and sp that receives the performance counter values from the ps scripts)
Note, scripted on SQL2005, so for SQL200, som mods will be needed
Creates the following (4 objects):
tables: tmonitor_computer, tmonitor_performanceCounter, tmonitor_performaceCounterValue
sp: monitor_performanceCounterValue_add

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tmonitor_computer]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[tmonitor_computer](
	[computer] [varchar](20) NOT NULL,
 CONSTRAINT [PK_tmonitor_computer] PRIMARY KEY CLUSTERED 
(
	[computer] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tmonitor_performanceCounterValue]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[tmonitor_performanceCounterValue](
	[monitorDate] [datetime] NOT NULL CONSTRAINT [DF_tmonitor_performanceCounter__monitorDate]  DEFAULT (getutcdate()),
	[counterID] [smallint] NOT NULL,
	[value] [numeric](18, 2) NOT NULL,
 CONSTRAINT [PK_tmonitor_performanceCounter] PRIMARY KEY CLUSTERED 
(
	[monitorDate] ASC,
	[counterID] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tmonitor_performanceCounter]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[tmonitor_performanceCounter](
	[counterID] [smallint] IDENTITY(1,1) NOT NULL,
	[object] [varchar](80) NOT NULL,
	[instance] [varchar](8) NOT NULL,
	[counter] [varchar](32) NOT NULL,
	[computer] [varchar](20) NOT NULL,
 CONSTRAINT [PK_tmonitor_counter] PRIMARY KEY CLUSTERED 
(
	[counterID] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY],
 CONSTRAINT [UC_tmonitor_counter__object_instance_counter_computer] UNIQUE NONCLUSTERED 
(
	[object] ASC,
	[instance] ASC,
	[counter] ASC,
	[computer] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[monitor_performanceCounterValue_add]') AND type in (N'P', N'PC'))
BEGIN
EXEC dbo.sp_executesql @statement = N'
 
CREATE procedure [dbo].[monitor_performanceCounterValue_add]
(
	@object varchar(80)
	,@instance varchar(8)
	,@counter varchar(32)
	,@computer varchar(20)
	,@value numeric(18,2)
)
as
set nocount on

declare @counterID smallint
set @counterID = (	select	counterID
					from	dbo.tmonitor_performanceCounter
					where	object = @object
							and instance = @instance
							and counter = @counter
							and computer = @computer)

if @counterID is null
begin
	insert	dbo.tmonitor_computer
	(
		computer
	)
	select	@computer
	where	@computer not in(select computer from dbo.tmonitor_computer)
	
	insert	dbo.tmonitor_performanceCounter
	(
		object
		,instance
		,counter
		,computer
	)
	values
	(
		@object
		,@instance
		,@counter
		,@computer
	)
	set @counterID = scope_identity()
end

insert	dbo.tmonitor_performanceCounterValue
(
	monitorDate
	,counterID
	,value
)
values
(
	default
	,@counterID
	,@value
)


' 
END
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_tmonitor_performanceCounterValue_REF_tmonitor_performanceCounter__counterID__counterID]') AND parent_object_id = OBJECT_ID(N'[dbo].[tmonitor_performanceCounterValue]'))
ALTER TABLE [dbo].[tmonitor_performanceCounterValue]  WITH CHECK ADD  CONSTRAINT [FK_tmonitor_performanceCounterValue_REF_tmonitor_performanceCounter__counterID__counterID] FOREIGN KEY([counterID])
REFERENCES [dbo].[tmonitor_performanceCounter] ([counterID])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[tmonitor_performanceCounterValue] CHECK CONSTRAINT [FK_tmonitor_performanceCounterValue_REF_tmonitor_performanceCounter__counterID__counterID]
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_tmonitor_performanceCounter_REF_tmonitor_computer__computer__computer]') AND parent_object_id = OBJECT_ID(N'[dbo].[tmonitor_performanceCounter]'))
ALTER TABLE [dbo].[tmonitor_performanceCounter]  WITH CHECK ADD  CONSTRAINT [FK_tmonitor_performanceCounter_REF_tmonitor_computer__computer__computer] FOREIGN KEY([computer])
REFERENCES [dbo].[tmonitor_computer] ([computer])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[tmonitor_performanceCounter] CHECK CONSTRAINT [FK_tmonitor_performanceCounter_REF_tmonitor_computer__computer__computer]


------------------------------------------------------------------------------------------------------------------------------------------------------------------

2. include_monitor_performanceCounterValue.ps1 (this is a ps script that is "included" in other scripts just to call the database)
Save this as include_monitor_performanceCounterValue.ps1, you will need to modify the connection string.

################################################################
# 
# include file for scripts that query the Win32_PerfFormattedData_XXX counters
# and call the monitor_performanceCounterValue_add procedure
#
################################################################

# initialize variables and db connection
$cn = new-object system.data.SqlClient.SqlConnection("Data Source=dbServer;Integrated Security=SSPI;Initial Catalog=dbName");
$cmd = new-object system.Data.Sqlclient.SqlCommand("monitor_performanceCounterValue_add", $cn);

$cmd.CommandType = [System.Data.CommandType]"StoredProcedure"

$cmd.Parameters.Add("@object",[System.Data.SqlDbType]"VarChar",80) | Out-Null
$cmd.Parameters.Add("@instance",[System.Data.SqlDbType]"VarChar",8) | Out-Null
$cmd.Parameters.Add("@counter",[System.Data.SqlDbType]"VarChar",32) | Out-Null
$cmd.Parameters.Add("@computer",[System.Data.SqlDbType]"VarChar",20) | Out-Null
$cmd.Parameters.Add("@value",[System.Data.SqlDbType]"Decimal") | Out-Null
$cmd.Parameters["@value"].Precision = 11
$cmd.Parameters["@value"].Scale = 2

# function for saving to db
function monitor_performanceCounterValue_add([string] $object, [string] $instance, [string] $counter, [string] $computer, [decimal] $value)
{
	$cmd.Parameters["@object"].Value = $object
	$cmd.Parameters["@counter"].Value = $counter
	$cmd.Parameters["@instance"].Value = $instance
	$cmd.Parameters["@computer"].Value = $server
	$cmd.Parameters["@value"].Value = $value
	$cn.Open()
	$cmd.ExecuteNonQuery() | Out-Null
	$cn.Close()
}

------------------------------------------------------------------------------------------------------------------------------------------------------------------

3. processor.ps1 (a sample powershell script to collect processorload counters)
Just save this as processor.ps1
You need to modify the array of servers to monitor

################################################################
# 
# monitors processor usage
# uses db function in include_monitor_performanceCounterValue.ps1 to save
#
################################################################

# include files
. .\include_monitor_performanceCounterValue.ps1

# declare an array of the servers to monitor
$servers = @("SERVER1","SERVER2","SERVER3")

# initialize variables
$pollIntervallSeconds = 10

#everloop
while($true)
{
	#loop the servers
	foreach($server in $servers)
	{
		trap [System.Data.SqlClient.SqlException] { break; } #cannot reach the db!
	
		$processor = Get-WmiObject -class Win32_PerfFormattedData_PerfOS_Processor -Property Name,PercentProcessorTime -computerName $server | where{$_.Name -eq "_Total"}
		if($processor -ne $null)
		{
			# if the system only has one processor, we don't get an array of objects but a single object
			if($processor -is [array])
			{
				for($i = 0; $i –lt $processor.Count; $i++)
				{
					monitor_performanceCounterValue_add "Processor" $processor[$i].Name "PercentProcessorTime" $server ([decimal]$processor[$i].PercentProcessorTime)
				}
			}
			else
			{
				monitor_performanceCounterValue_add "Processor" $processor.Name "PercentProcessorTime" $server ([decimal]$processor.PercentProcessorTime)
			}
			$processor = $null
		}
	}
	Start-Sleep -s $pollIntervallSeconds
}

# "cleanup" doubtfully reached ;-)
$cmd = $null
$cn = $null

------------------------------------------------------------------------------------------------------------------------------------------------------------------
4. disk.ps1 (a sample powershell script to collect logical disk counters)
just save this as disk.ps1
You need to modify the array of servers to monitor

################################################################
# 
# monitors disk space and usage
# uses db function in include_monitor_performanceCounterValue.ps1 to save
#
################################################################

# include files
. .\include_monitor_performanceCounterValue.ps1

# declare an array of the servers to monitor
$servers = @("SERVER1","SERVER2","SERVER3")

#loop the servers
foreach($server in $servers)
{
	trap [System.Data.SqlClient.SqlException] { break; } #cannot reach the db!
	# we use the -ErrorAction SilentlyContinue for the gwmi call, since it is a non-terminating error, and thus does not get caught in a trap

	$disk = Get-WmiObject -query "SELECT Name,CurrentDiskQueueLength,PercentFreeSpace,FreeMegabytes FROM Win32_PerfFormattedData_PerfDisk_LogicalDisk" -computerName $server -ErrorAction SilentlyContinue | where{$_.Name -ne "_Total"}
	if($disk -ne $null)
	{
		# if the system only has one disk, we don't get an array of objects but a single object
		if($disk -is [array])
		{
			for($i = 0; $i –lt $disk.Count; $i++)
			{
				monitor_performanceCounterValue_add "LogicalDisk" $disk[$i].Name "CurrentDiskQueueLength" $server ([decimal]$disk[$i].CurrentDiskQueueLength)
				monitor_performanceCounterValue_add "LogicalDisk" $disk[$i].Name "FreeMegabytes" $server ([decimal]$disk[$i].FreeMegabytes)
				monitor_performanceCounterValue_add "LogicalDisk" $disk[$i].Name "PercentFreeSpace" $server ([decimal]$disk[$i].PercentFreeSpace)
			}
		}
		else
		{
			monitor_performanceCounterValue_add "LogicalDisk" $disk.Name "CurrentDiskQueueLength" $server ([decimal]$disk.CurrentDiskQueueLength)
			monitor_performanceCounterValue_add "LogicalDisk" $disk.Name "FreeMegabytes" $server ([decimal]$disk.FreeMegabytes)
			monitor_performanceCounterValue_add "LogicalDisk" $disk.Name "PercentFreeSpace" $server ([decimal]$disk.PercentFreeSpace)
		}
		$disk = $null
	}
}

# cleanup
$cmd = $null
$cn = $null
  Previous Topic Topic Next Topic  
 New Topic  Reply to Topic
 Printer Friendly
Jump To:
SQL Server Forums © 2000-2009 SQLTeam Publishing, LLC Go To Top Of Page
This page was generated in 0.08 seconds. Powered By: Snitz Forums 2000 Version 3.4.03