Like most DBAs, I collect different statistics on the SQL servers I’m responsible for. I want to be able to track database growth over time. I also want a way to quickly check how much space is available. At first I wrote a few local scripts and saved to tables in a local database. While learning SSIS for the 70-448 exam I created a package to move the data from the local servers to a central repository and output the last two collections to an Excel spreadsheet. That works pretty well. But I’m always looking for new and possibly better ways to perform my day to day tasks. And I just got a list of new SQL servers to monitor, and I wasn’t able to fully port my SSIS solutions to include some of those servers. So I decided to switch over to PowerShell.
This post isn’t meant to be an overview or PowerShell, or even PowerShell for SQL. Those topics have been covered elsewhere and much more thoroughly than I can here. If you need a starting point for PowerShell I’ll put some links to sites to get you started at the end of this post. Today I’m going to cover two specific tasks; getting total and free space per drive and space used by each database for a list of servers. The results will be stored in a central database that I can query later for trends.
For this post my central repository is called “MONITOR” and the database is called “ServerStats”. Inside ServerStats I’ve created the two tables below;
CREATE TABLE dbo.DBStats(
ServerName sysname NOT NULL,
RunDate datetime NOT NULL,
DBName sysname NOT NULL,
Name sysname NOT NULL,
[FileName] nchar(520) NOT NULL,
TotalSize float NOT NULL,
UsedSpace float NOT NULL,
FreeSpace float NOT NULL,
FileID int NOT NULL
)
CREATE TABLE dbo.DriveSpace(
ServerName sysname NOT NULL,
Drive char(3) NULL,
TotalSpaceInGB numeric(6, 2) NULL,
FreeSpaceInGB numeric(6, 2) NULL,
RunDate datetime NULL
)
To run the PowerShell scripts you’ll need to get a few things. In my profile I load the SQLPSX snap-ins as well as Invoke-SQLCMD2, Write-DataTable, and Out-DataTable. See the Links and Downloads section at the bottom of this post for more information on these modules.
My first script is for getting the drive size. I simply loop through an array of servers, then query WMI for hard drive information with Get-WMIObject. I don’t want info on CD drives so I only filter for where the drive type is 3. I send the result to a data table object ( | Out-DataTable). Finally I write the data table back to my monitoring server with Write-DataTable. Notice I declare the variable $unit as “GB”. PowerShell then gives me my data in gigabytes. I could change this to “MB” if I want to see the size in megabytes instead.
$srvlist = @(get-content ".\ServerList.txt")
$unit = "GB"
$measure = "1$unit"
$wmiQuery = "
SELECT SystemName, Name, DriveType, FileSystem, FreeSpace, Capacity, Label
FROM Win32_Volume WHERE DriveType = 3
"@
foreach ($instance in $srvlist)
{
$dt = Get-WmiObject -ComputerName $instance -Query $wmiQuery |
Select-Object SystemName, Name, @{Label"TotalSpaceIn$unit"; Expression={"{0:n2}" -f ($_.Capacity/$measure)}}, @{Label="FreeSpaceIn$unit"; Expression={"{0:n2}" -f ($_.FreeSpace/$measure)}} |
Where-Object {$_.Name -NotLike '\\?\*'} |
Sort-Object Name | Out-DataTable
Write-DataTable -ServerInstance "MONITOR" –Database ServerStats-TableName DriveSpace -data $dt
}
My second script, for getting database sizes, is similar. I still loop through an array of servers. But this time for each instance I run a dynamic SQL script by calling Invoke-Sqlcmd2. That script creates a temp table, then loops through each database for the sizes. I’m using a trusted connection but if I wasn’t I could supply –UserName and -Password to Invoke-Sqlcmd2.
$srvlist = @(get-content ".\SQLServerList.txt")
foreach ($instance in $srvlist)
{
$dt = Invoke-Sqlcmd2 -ServerInstance $instance -Database master "CREATE TABLE #dbStats(
[Servername] [sysname] NULL,
[RunDate] [datetime] NULL,
[DBName] [sysname] NULL,
[Name] [sysname] NULL,
[FileName] [nchar](520) NULL,
[TotalSize] [float] NULL,
[UsedSpace] [float] NULL,
[FreeSpace] [float] NULL,
[FileID] [int] NULL)
EXEC sp_msforeachdb 'USE [?]
DECLARE @PageSize float
SELECT @PageSize = v.low /1024.0 FROM master.dbo.spt_values v WHERE v.number = 1 AND v.type = ''E''
INSERT INTO #dbStats
SELECT @@servername AS ServerName,
CONVERT(DATETIME, CONVERT(CHAR(12), GETDATE(), 101)) AS RunDate,
''?'' AS DBName,
RTRIM(s.name) AS [Name],
RTRIM(s.filename) AS [FileName],
(s.size * @PageSize) AS [TotalSize],
CAST(FILEPROPERTY(s.name, ''SpaceUsed'') AS float)* CONVERT(float, 8) AS [UsedSpace],
(s.size * @PageSize) - CAST(FILEPROPERTY(s.name, ''SpaceUsed'') AS float) * CONVERT(float, 8) AS [FreeSpace],
CAST(s.fileid AS int) AS [ID]
FROM sysfiles AS s'
SELECT * FROM #dbStats"
Write-DataTable -ServerInstance "MONITOR" –Database ServerStats –TableName DBStats -Data $dt
}
And that’s just about it. I’ve got a SQL Agent job on the monitoring server that runs both PowerShell scripts once a week. The nice thing, at least so far, is that I can run these scripts against different SQL servers and OS versions. My list has servers running Windows 2000 to 2008 R2, and SQL instances in the same time frame. There’s even a few Express editions in there. My next step will be to create an Excel spreadsheet to view the data. I’m thinking PowerView for that.
I’d be interested in hearing how you work with SQL and PowerShell. Just leave a comment. Or let me know how I can improve my scripts.
Links and Downloads
- Get the SQL Extensions for PowerShell from Codeplex.
- Invoke-sqlcmd2, Write-DataTable, and Out-DataTable were also written by Chad Miller (Blog | Twitter) and are available on the TechNet site. All these modules are well documented.
- There are a lot of good sites that can get you started with PowerShell. A simple Google search will turn up plenty. But start with Hey Scripting Guy! Also follow Ed Wilson and his Scripting Wife Teresa on Twitter
- One of my favorites sites is Allen White’s (Blog | Twitter). Allen also presents at numerous SQLSaturday events. Find one near you where he’s speaking. For that matter, SQLSaturdays usually have at least one session dedicated to PowerShell.
- Another good PowerShell site is is the Stairway to PowerShell series on SQLServerCentral, written by Ben Miller.