Identify the last full, log and differential backup date and times for each database.

The following script is very useful if you just want to find out when each database was last backed up. It returns the database name, it’s recovery type, (important so that missing log backups for SIMPLE recovery can be ignored), and the date and time of each full, log and differential backup. This query could be used in an Agent job which could be scheduled to run each day and look for any databases that (a), haven’t had a full backup for more than a day and (b), any databases which are using the full recovery model, which haven’t had a transaction log backup for more than a day.

SELECT DISTINCT D.database_id AS Database_Id,
                D.NAME        AS Database_Name,
Isnull(CONVERT(VARCHAR(25), Max(F.backup_start_date)
partition BY F.database_name ),
113), ‘NEVER’)
AS Last_Full_Backup_Date,
CASE D.recovery_model_desc
ELSE Isnull(CONVERT(VARCHAR(25), Max(L.backup_start_date)
partition BY L.database_name ), 113),
END           AS Last_Log_Backup_Date,
                Isnull(CONVERT(VARCHAR(25), Max(I.backup_start_date)
partition BY I.database_name ),
113), ‘NEVER’)
AS Last_Diff_Backup_Date
FROM   sys.databases D
LEFT OUTER JOIN msdb..backupset F
ON F.database_name = D.NAME
AND F.type = ‘D’
LEFT OUTER JOIN msdb..backupset L
ON L.database_name = D.NAME
AND L.type = ‘L’
LEFT OUTER JOIN msdb..backupset I
ON I.database_name = D.NAME
AND I.type = ‘I’
ORDER  BY D.database_id; 


Never forget what that database is used for, with SQL Server Extended Properties!

When I create a new database, I always set the Extended Properties of the database so that I can record a few key pieces of information. This is really useful to be able to quickly identify what the database is used for, who the business owner is, the date it was created and any other information that may be valuable, but easily forgotten.  There are numerous times people have asked me what the database is for such and such an application, especially when there are a few versions of the same software being used across the organisation and each one has its own database named slightly differently.

You can see the extended properties of a database by right clicking on the database object in SSMS and selecting ‘Properties’. Then select ‘Extended Properties’.


I usually keep to the same format when recording property values, namely:

  • A description of the database, including the application that uses it.
  • The date it was created.
  • The business owner, or team which supports the application.
  • The server name of each server that connects to it.  This is especially useful when the database has to be moved to a new or upgraded SQL Server and you need to know which servers have to have their connection strings changed.

To fill in the extended property I run the following script on the database in question, adding in the values for each property type:

USE []
EXEC sp_addextendedproperty @name=N’Contact’, @value=N” — Example: Accounts Team, John Smith
EXEC sp_addextendedproperty @name=N’Created’, @value=N” — Example: 01/01/2015
EXEC sp_addextendedproperty @name=N’Description’, @value=N” — Example: Used for Payroll data, must be setup with Full Recovery.
EXEC sp_addextendedproperty @name=N’ApplicationServer’, @value=N” — Example: AppServer1, AppServer15

Once the databases have had their properties set, you can then periodically run reports on them. This can be useful if you want to find out if a database is still used, but don’t know who the contact is or what the database is actually used for. To do this, the following script can be run to generate a report:

— Create a global tempory table to hold the results.
CREATE TABLE ##results
(id INT IDENTITY(1, 1) ,
DatabaseName VARCHAR(50) ,
Description VARCHAR(250) ,
Contact VARCHAR(250));

— This first command will simply add all databases to the table
DECLARE @command VARCHAR(1000);
INSERT INTO ##results
FROM sys.databases
WHERE name NOT IN ( ‘master’, ‘tempdb’, ‘model’, ‘msdn’ );

— Build the update command to get the description and Contact information for each database.
SELECT @command = ‘USE [?] Update ##results
SET Description = CONVERT(VARCHAR(250), Description.value),
Contact = CONVERT(VARCHAR(250), Contact.value)
FROM sys.extended_properties Description,
sys.extended_properties Contact
WHERE Description.class_desc =”DATABASE” AND = ”MS_Description”
AND Contact.class_desc =”DATABASE” AND = ”MS_Contact”
AND ##results.DatabaseName = DB_NAME(DB_ID());

— Execute the command on each database
EXEC sp_MSforeachdb @command;

— Select the results and drop the table
FROM ##results
ORDER BY DatabaseName;

DROP TABLE ##results;

This results in the following output:


What is also useful, is this report shows any databases that don’t have the properties set. This means you can run this periodically to make sure you keep the records updated.  You can change the query used in the report to generate any information held in the extended properties.

For more information on Extended Properties check out BOL, or this blog post by Glen Berry which details the use of Extended Properties in great detail.

Identify the size and document count of a single SharePoint Site

The following query is useful, if you have a SharePoint site which uses one content database and all websites hang off the one top url.  The script can be used to identify the total size of each site and the number of documents contained in the site.  

USE [<YourContentDatabaseName>]; — don’t forget the semi-colon!

folderhierachy as(
select f.fullurl, (((sum(cast(d.size as bigint))) / 1024) /1024) as sizeinMB, count(d.Id) as DocCount
from webs f, docs d, lists l
d.webid =
l.tp_id = d.listid
d.size > 0
(d.LeafName NOT LIKE ‘%.stp’)
AND (d.leafname NOT LIKE ‘%.aspx’)
AND (d.leafname NOT LIKE ‘%.xfp’)
AND (d.leafname NOT LIKE ‘%.dwp’)
AND (d.leafname NOT LIKE ‘%template%’)
AND (d.leafname NOT LIKE ‘%.inf’)
AND (d.leafname NOT LIKE ‘%.css’)
group by f.FullUrl
select substring(fullurl,1,charindex(‘/’,fullurl)) as Url, sum(sizeinMB) as “Size In MB”, sum(DocCount) as “Document Count”
from folderhierachy
group by substring(fullurl,1,charindex(‘/’,fullurl))
order by Url, [Size In MB] desc;


Red Gate SQL Monitor Metric – New logins to the Sysadmin role.

Red Gate SQL Monitor Metric – New logins to the Sysadmin role.

Another one of my SQL Monitor custom metrics has been published by Red Gate.  This one generates an alert when the count of server principles who are added to the sysadmin server role changes.  It is very useful when multiple members of an IT team may have a DBA support function and are inclined to simple add users with sysadmin roles. This metric can be used to alert when this happens so it can be checked and verified in case it causes a security risk.

Weekly SQL: Filter on SP_WHO2 in a table.

This is a new section of my blog, where I plan to publish a SQL script on a weekly basis.  These will be scripts I either use on a daily basis or ones which I find particularly interesting and worth sharing.

This week, the following script is really useful for finding out who is connected to a particular database. It uses the SP_WHO2 special procedure and allows the data to be filtered.  I am not sure where I got this script from, but it is not mine, but I must use it every day:

Run this on the database you wish to query:

ProgramName VARCHAR(MAX),

INSERT INTO @Table EXEC sp_who2

FROM @Table
where dbname = db_name(db_id())

You can add to the where clause to filter on the different columns.

I also use this script if I am restoring a database and need to quickly kill of any users.  By adding the following extra code after the above, it will generate a the kill commands which I can copy and paste to a new query window:

–Generate a kill script
SELECT ‘kill ‘ + cast(spid as varchar(3))
FROM @table
WHERE dbname = db_name(db_id())

First Redgate SQL Metric published

First Redgate SQL Metric published

A while ago, my first Red Gate SQL metric was published for use with Red Gates excellent SQL Monitor software.  This metric allows you to be alerted when a transaction log grows over a defined threshold.  This can be particularly useful if a process is stopping the log from truncating or the transaction backups have not been running successfully.

SPN Setup for Double hop from Client (IE) to IIS 8 to SQL Server (2012)

The following is the required steps to set up kerberos authentication for a client to sql server.

This is a rough post, created purely for self reference.  A lot of this work is talked about at the following location


  • Open ISS Manager and go to application pools.
  • Set the correct application pool to use a dedicated user – right click and slect advanced settings. Change identity to the domain user required. If you’re not sure what application pool is the being used by the web app, stop them all and then start them individually, whilst refreshing the web app. When the correct one is used, the web app should work (somewhat!).
  • Next, go to the web application web site in IIS manager. Double click authentication and enable ASP.NET Impersonation (right click and select enable).
  • Right click on Windows Authentication and enable too.
  • Right click on Windows authentication and select Advance Settings and untick Enable Kernel-mode Authentication.
  • Click ok then right click on Windows Authentication and select providers.
  • Add Negotiate:Kerberos from the available providers drop down list.  Make sure this is the top of the list of enabled providers, above negotiate.

On a domain connected computer:

Add the SPN’s:

  • Open a cmd window and add an spn for the service account that the web app is running under. This is the domain account you set for the application pool.  This SPN should be for HTTP service for the URL of the server. In this case below the server name:
    setspn -A HTTP/WebserverName domain\domainuser
    i.e: setspn -A HTTP/SGBB1234 CONTOSO\WebAppServiceUser
  • Add the SPN for the Fully qualified domain name too, i.e.:
    setspn -A HTTP/SGBB1234.CONTOSO.UK.COM CONTOSO\WebAppServiceUser
  • Now check the spn is set for the SQL Server Service account. This is the account the SQL Server is running under:
    setspn -l SQLServerServiceAccount
  • If nothing is listed, then add the spn for the database instance using port number and instance name:
    setspn -A MSSQLSvc/ServerNameFQN:portnumber domain\SQLServiceAccount
    setspn -A MSSQLSvc/ServerNameFQN:InstanceName domain\SQLServiceAccount
    setspn -A MSSQLSvc/DBServer.Contoso.UK.COM:1453 contoso\Account1
    setspn -A MSSQLSvc/DBServer.Contoso.UK.COM:Instance1 contoso\Account1
  • After you have setup the SPN’s using the SETSPN commands for the instance and port of the SQL Server Service Account, run the command <code>dsacls “CN=<CommonName>, OU=<OrganisationUnit>, DC=<DomainComponent>” /G SELF:RPWP;”servicePrincipalName”</code>
    Change the CN, OU and DC values to be appropriate for the service account.  If you look at the SETSPN command for the service account, this will provide you with these values and so the whole string can be copied and pasted I.e.
    <code>dsacls “CN=Account1,OU=Service Accounts, OU=Administrative, OU=HO, DC=contoso,DC=ad,DC=contoso,DC=com” /G SELF:RPWP;”servicePrincipalName”</code>
    The dsacls command is part of the AD feature pack.  You should see the command complete successfully.

    Once all is done, run the command setspn -X to check for any duplicates. Remove any duplicate SPN’s from the incorrect location.

  • You will then need to restart SQL so that it can register the SPN in AD.

Now setup Delegation:

Once the SPN’s are set then the delegation tab will be visible in AD for users:

  • Open AD Users and Computers and navigate to the domain user used to run the app pool web service.
  • Click on Delegation tab and select Trust this user for delegation any service, or to a specific service if more granulatrity required.
  • Do the same for the IIS server in AD too.

Once all the above is complete, restart IIS.

On the client pc, make sure no kerberos tickets are cached and causing a incorrect response.  Do this by opening a cmd window and typing “klist purge”. It should say tickets cleared.

Now do a ctrl + F5 refresh in IE, and the kerberos authentication should work!

Hopefully that is it!