A script to find/drop all orphaned users in SQL Server Databases


Scenario Proposal

One of my many day to day duties includes administering a database (actually many databases) for a Human Resources application. This application uses SQL logins for data access. This is a database I inherited so I had no input on how things were setup or administered. In the past the application administrator used a script to create new users but the script did not work well and frequently caused errors. When a user is created for the application a SQL login is created then a database user is created in many databases.

Since this script did not work well and I was the one that usually had to clean up the mess I decided to write a new script to create the users. After writing the script I also decided to write another script to delete users since the application did not provide a process for doing this. As I was writing the script to delete users it occurred to me that there may be orphaned users in many of the databases because deleting users has always been a manual process and it would be very easy to miss one. After checking a few databases and finding orphaned users I tried to find a script to clean up these orphaned users and was surprised that I could not find a script on the internet that did what I wanted so I decided to write my own and pass the information on to others.

 

Solution

What Is An Orphaned SQL User?

So, what is an orphaned SQL user? An orphaned user is a database user that does not have an associated SQL login. There are a number of ways a user can become orphaned. The most common way is when a database from a different server is restored. When a database is backed up and restored the database users are also backed up and restored with the database, but the SQL login is not. If a database is restored to the same server the backup came from and the logins already exist then the database users will not be orphaned because security identifiers (SID) will be the same. If a database is restored to a different server and there are logins with the same name chances are the database users will be orphaned because the identifiers are not the same. And if the logins do not exist at all the database users will be orphaned. Another way database users can be orphaned is if the SQL login is deleted without checking for database users.

Find Orphans In All Databases

In my quest, I did find scripts but none did all that I wanted or did it the way I wanted. So I used some of these scripts as models and wrote my own script to get the results I wanted. My purpose in creating this script was twofold. First find all orphaned users in all databases in a server instance and second delete those users if desired. One difficulty encountered when deleting database users is that the user may own objects in the database and cannot be dropped until the object is dropped or ownership is transferred. In my case all users owned a schema so my script had to deal with a schema owned by the user. I wrote the script to store information about orphaned users in a local temporary table, then the temporary table could be used to drop the schema and user.

Find Orphaned Database Users Script

Use master
Go
Create Table #Orphans
 (
  RowID     int not null primary key identity(1,1) ,
  TDBName varchar (100),
  UserName varchar (100),
  UserSid varbinary(85)
)
SET NOCOUNT ON
 DECLARE @DBName sysname, @Qry nvarchar(4000)
SET @Qry = ”
SET @DBName = ”
WHILE @DBName IS NOT NULL
BEGIN
   SET @DBName =
     (
  SELECT MIN(name)
   FROM master..sysdatabases
   WHERE
   /** to exclude named databases add them to the Not In clause **/
   name NOT IN
     (
      ‘model’, ‘msdb’,
      ‘distribution’
     ) And
     DATABASEPROPERTY(name, ‘IsOffline’) = 0
     AND DATABASEPROPERTY(name, ‘IsSuspect’) = 0
     AND name > @DBName
      )
   IF @DBName IS NULL BREAK
        
                Set @Qry = ‘select ”’ + @DBName + ”’ as DBName, name AS UserName,
                sid AS UserSID from [‘ + @DBName + ‘]..sysusers
                where issqluser = 1 and (sid is not null and sid <> 0x0)
                and suser_sname(sid) is null order by name’
Insert into #Orphans Exec (@Qry)
 
 End
Select * from #Orphans
/** To drop orphans uncomment this section
Declare @SQL as varchar (200)
Declare @DDBName varchar (100)
Declare @Orphanname varchar (100)
Declare @DBSysSchema varchar (100)
Declare @From int
Declare @To int
Select @From = 0, @To = @@ROWCOUNT
from #Orphans
–Print @From
–Print @To
While @From < @To
Begin
  Set @From = @From + 1
 
  Select @DDBName = TDBName, @Orphanname = UserName from #Orphans
   Where RowID = @From
     
   Set @DBSysSchema = ‘[‘ + @DDBName + ‘]’ + ‘.[sys].[schemas]’
   print @DBsysSchema
   Print @DDBname
   Print @Orphanname
   set @SQL = ‘If Exists (Select * from ‘ + @DBSysSchema
                          + ‘ where name = ”’ + @Orphanname + ”’)
    Begin
     Use ‘ + @DDBName
                                        + ‘ Drop Schema [‘ + @Orphanname + ‘]
    End’
   print @SQL
   Exec (@SQL)
    
    Begin Try
     Set @SQL = ‘Use ‘ + @DDBName
                                        + ‘ Drop User [‘ + @Orphanname + ‘]’
     Exec (@SQL)
    End Try
    Begin Catch
    End Catch
  
 End
**/
 
Drop table #Orphans

 Things To Note About This Script

Databases can be excluded from the search by adding the database name to exclude in the ‘NOT IN’ where clause. If the “Drop Orphans’ section is uncommented the script will drop any schema that the orphaned user owns then drop the orphaned user, there is no option to skip a schema/user. The script will not check for other objects that may be owned by the user. I have tested the script on SQL 2005 and SQL 2008 R2.

 

 

Thanks for reading this article,

Next steps :

  1. Add this script to your database toolkit
  2. Share this with your colleagues because Sharing is Learning
  3. Comment below if you need any assistance