I'm attempting to write a SSIS package that loops through a list of databases on different servers and returns a list of users for each database, including their roles. The following code runs successfully when executed in SSMS against databases on SQL 2005,
2008/R2, and 2012.
/******************************************************
Declare variables to work with
******************************************************/
DECLARE @U1 as table
([principal_id] int
,[RowNo] int
)
DECLARE @R2 as table
([principal_id] int
,[db_Role] nvarchar(128)
,[RowNo] int
)
DECLARE @T3 as table
([ServerName] nvarchar(128)
,[db_Name] nvarchar(128)
,[User_Name] nvarchar(128)
,[User_Type] nvarchar(60)
,[db_Roles] nvarchar(128)
)
DECLARE @roles as nvarchar(128)
DECLARE @principal_id as int
DECLARE @I as int
DECLARE @MaxI as int
DECLARE @J as int
DECLARE @MaxJ as int
/******************************************************
Insert users into table variable
******************************************************/
INSERT INTO @U1
SELECT principal_id,
ROW_NUMBER() OVER(ORDER BY principal_id) AS RowNo
FROM sys.database_principals AS U
WHERE U.[type] IN ('S','U')
AND U.[name] NOT IN ('dbo','guest','INFORMATION_SCHEMA','sys')
/******************************************************
Insert roles into table variable
******************************************************/
INSERT INTO @R2
SELECT M.member_principal_id AS principal_id,
R.[name] AS [db_Role],
ROW_NUMBER() OVER(PARTITION BY M.member_principal_id ORDER BY R.[name]) AS RowNo
FROM sys.database_role_members AS M
INNER JOIN sys.database_principals AS R ON M.role_principal_id = R.principal_id
/******************************************************
Need to start looping through each role
******************************************************/
SET @I = 1
SELECT @MaxI = MAX([RowNo]) FROM @U1
WHILE @I <= @MaxI
BEGIN
/******************************************************
Get all of the roles and put them into a variable
******************************************************/
SET @J = 1
SELECT @principal_id = [principal_id] FROM @U1 WHERE RowNo = @I
SELECT @MaxJ = MAX([RowNo]) FROM @R2 WHERE [principal_id] = @principal_id
SELECT @roles = ''
WHILE @J <= @MaxJ
BEGIN
SELECT @roles = @roles + [db_Role] + '; '
FROM @R2 AS R
WHERE principal_id = @principal_id
AND RowNo = @J
SET @J = @J+1
PRINT @Roles
END
/******************************************************
Put the results into the user table
******************************************************/
INSERT INTO @T3
SELECT CONVERT(nvarchar(128),@@SERVERNAME) AS [ServerName],
CONVERT(nvarchar(128),DB_NAME()) AS [db_Name],
CONVERT(nvarchar(128),P.[name]) AS [User_Name],
CONVERT(nvarchar(60),P.[type_desc]) AS [User_Type],
CONVERT(nvarchar(128),@roles) AS [db_Roles]
FROM @U1 AS U
INNER JOIN sys.database_principals AS P ON U.principal_id = P.principal_id
WHERE U.principal_id = @principal_id
SET @I = @I+1
END
SELECT * FROM @T3 ORDER BY [User_Name]
It all starts falling down when I try and put this into a data flow task as a source. The connection manager for the OLE DB Source is dynamically changed and this code called for each new connection by placing the data flow task within a loop. The connection
string for the connection manager is an expression defined as follows:
"Data Source="+ @[User::ServerName] +";Initial Catalog="+ @[User::DBName] +";Provider=SQLNCLI11.1;Integrated Security=SSPI;Auto Translate=False;"
As I said, the code runs fine when executed in SSMS, but when run through SSIS only works for SQL 2012 servers. If I try to return information from a SQL 2005 (or other) server I get the following message and the packages refuses to run:
"no column information was returned by the sql command"
After exploring this issue I've attempted a few solutions (including prefixing my code with SET FMTONLY OFF and ensuring that the final result always returns a value), but to no avail.
I'm at the point that the only solution I can think of is to create this as a stored procedure / table-values function on every database (or at least every server), but this strikes me as impractical.
Suggestions?