This is a partial update of my “DBA Audit” post, using code more suited to SQL 2014 and beyond.
Before a migration I created a job called “Audit Logins” scheduled to run every minute to help flag unused logins.
The first step ‘setup’ creates and populates a table with all enabled logins …
/* initial setup */ /* create table */ CREATE TABLE [master].[dbo].[LoginAudit] ( LoginName VARCHAR(200), LastLoginDate DATETIME) /* populate with logins */ INSERT INTO [master].[dbo].[LoginAudit] (LoginName, LastLoginDate) SELECT [name], NULL FROM [master].[sys].[server_principals] WHERE type 'R' /* is not a Role */ AND is_disabled 1; /* is not Disabled */
Step-1 fails after the first run by design (as the table already exists) and continues onward with step-2 ‘update’ …
/* update logins */ SELECT MAX(login_time) LoginTime, login_name LoginName INTO #LoginTempTable FROM [sys].[dm_exec_sessions] WHERE login_name '' /* exclude ef */ GROUP BY login_name; UPDATE [master].[dbo].[LoginAudit] SET LastLoginDate = tmp.LoginTime FROM #LoginTempTable tmp WHERE LoginAudit.LoginName = tmp.LoginName;
I called it ~light as it is designed to have one row per login. Therefore if it is forgotten, and runs for years, the audit table will never grow.