This means that database users have no matching server logins.
That is, each database sys.database_principals has no match in sys.server_principals
For Windows logins this is easy. This generates your missing CREATE LOGINS
USE MyDB
SELECT
'CREATE LOGIN ' + QUOTENAME(SUSER_SNAME(sid)) + ' FROM WINDOWS'
FROM
sys.database_principals DP
WHERE
DP.type IN ('G', 'U')
AND
NOT EXISTS (SELECT * FROM sys.server_principals SP WHERE SP.sid = DP.sid);
For SQL Logins, you need to recreate it with the correct SID.
SELECT
'CREATE LOGIN ' + QUOTENAME(DP.name) +
' WITH PASSWORD = ''ChangeMe'', SID = ' +
CONVERT(varchar(128), sid, 1)
FROM
sys.database_principals DP
WHERE
DP.type = 'S' AND DP.principal_id > 4
AND
NOT EXISTS (SELECT * FROM sys.server_principals SP WHERE SP.sid = DP.sid);
Note that sp_change_users_login is deprecated.
Now, if your SQL Logins already exist, then the names match but the sid values are different. For this you use ALTER USER use the LOGIN option.
Finally, the SQL Login passwords can be recreated if you have a backup of the "old" master database. If you restore this as, say, FixLogins then you can use this
SELECT
'CREATE LOGIN ' + QUOTENAME(DP.name) +
' WITH PASSWORD = ' + CONVERT(varchar(256), SL.password_hash, 1) + ' HASHED, SID = ' +
CONVERT(varchar(128), DP.sid, 1)
FROM
sys.database_principals DP
JOIN
FixLogins.sys.sql_logins SL ON DP.sid = SL.sid
WHERE
DP.type = 'S' AND DP.principal_id > 4
AND
NOT EXISTS (SELECT * FROM sys.server_principals SP WHERE SP.sid = DP.sid);
Since you do not know the schema or tables names to grant them to, no to specifically doing it. You can add your AD account to the db_datareader
role within the model
database, and this should be copied into each database created on that instance.
In addition, if databases happen to get created via restore or anything other than create database statement you can use Policy Based Management rules to easily verify if your AD account is a member of that DB role and if not take an appropriate action.
Best Answer
If you could live with a finite time (minimum 10-seconds) between executions to catch new/restored databases, you could create a scheduled SQL Server Agent Job and put something like this in a T-SQL Job Step:-