Can we use 'xp_logininfo' to compare and find duplicate groups?

46 Views Asked by At

With 'xp_logininfo' we can pull members of AD Security Groups

/* all groups user is member and group granting access */
EXEC   xp_logininfo 'Domain\WindowsUser', 'all';

/* all user is in group */
EXEC   xp_logininfo 'Domain\WindowsGroup', 'members';

Problem: I have inherited many security groups and found duplicate: Groups either have the same members but different access or Same access different members in groups Some groups no longer have members at all

Idea: I want to find all the Windows Groups drop them in a table then (and this is where I need a smarted DBA) create a new table using 'xp_logininfo' to execute on every name name in the first table

select
      [name]
from [sys].[database_principals]
where [type] in ('G')

Insert Into #temptable1 ([name])

(theory)
EXEC   xp_logininfo '#temptable1', 'members';
CREATE TABLE #temptable2 ( [account name] nvarchar(128), [type] varchar(8), [privilege] varchar(8), [mapped login name] nvarchar(128), [permission path] nvarchar(128) )

INSERT INTO #temptable2 ([account name], [type], [privilege], [mapped login name], [permission path])

So far I am able to pull members of AD Security Groups 1 at a time but with over 800 groups just collecting the data and moving it into excel to compare has been a time consuming task.

If anyone has done this or has an idea how I can speed this up I'd love the assistance.

I'd like to add I'm dyslexic so if I need to re-explain any of this please let me know.

1

There are 1 best solutions below

0
Bad_sa_18456 On BEST ANSWER

Update: I found this: Enumerate Windows Group Members Lowell Izaguirre, 2017-02-24 (first published: 2016-03-17)

Info - https://www.sqlservercentral.com/articles/enumerate-windows-group-members Code - https://www.sqlservercentral.com/wp-content/uploads/2019/05/EnumerateWindowsGroupMembers.sql

I used this to write the results to a table and compared the data

    ...
    --###############################################################################################
    -- Quick script to enumerate Active directory users who get permissions from An Active Directory Group
    --###############################################################################################


    --a table variable capturing any errors in the try...catch below
    DECLARE @ErrorRecap TABLE
      (
         ID           INT IDENTITY(1, 1) NOT NULL PRIMARY KEY,
         AccountName  NVARCHAR(256),
         ErrorMessage NVARCHAR(256)
      ) 

    IF OBJECT_ID('tempdb.dbo.#tmp') IS NOT NULL
    DROP TABLE #tmp
    --table for capturing valid resutls form xp_logininfo
    CREATE TABLE [dbo].[#TMP] ( 
    [ACCOUNT NAME]       NVARCHAR(256)                        NULL ,
    [TYPE]               VARCHAR(8)                           NULL ,
    [PRIVILEGE]          VARCHAR(8)                           NULL ,
    [MAPPED LOGIN NAME]  NVARCHAR(256)                        NULL ,
    [PERMISSION PATH]    NVARCHAR(256)                        NULL )

    DECLARE @groupname NVARCHAR(256)
      --better practice cursor: all options
     declare c1 cursor LOCAL FORWARD_ONLY STATIC READ_ONLY for
      --###############################################################################################
      --cursor definition
      --###############################################################################################
       SELECT name 
       FROM master.sys.server_principals 
       WHERE type_desc =  'WINDOWS_GROUP' 
       --###############################################################################################
      OPEN c1
      FETCH NEXT FROM c1 INTO @groupname
      WHILE @@FETCH_STATUS <> -1
        BEGIN
          BEGIN TRY
            INSERT INTO #tmp([ACCOUNT NAME],[TYPE],[PRIVILEGE],[MAPPED LOGIN NAME],[PERMISSION PATH])
              EXEC master..xp_logininfo @acctname = @groupname,@option = 'members'     -- show group members
          END TRY
          BEGIN CATCH
            --capture the error details
            DECLARE @ErrorSeverity INT, 
                    @ErrorNumber INT, 
                    @ErrorMessage NVARCHAR(4000), 
                    @ErrorState INT
            SET @ErrorSeverity = ERROR_SEVERITY()
            SET @ErrorNumber = ERROR_NUMBER()
            SET @ErrorMessage = ERROR_MESSAGE()
            SET @ErrorState = ERROR_STATE()

            --put all the errors in a table together
            INSERT INTO @ErrorRecap(AccountName,ErrorMessage)
              SELECT @groupname,@ErrorMessage

              --echo out the supressed error, the try catch allows us to continue processing, isntead of stopping on the first error
            PRINT 'Msg ' + convert(varchar,@ErrorNumber) + ' Level ' + convert(varchar,@ErrorSeverity) + ' State ' + Convert(varchar,@ErrorState)
            PRINT @ErrorMessage
        END CATCH
        FETCH NEXT FROM c1 INTO @groupname
        END
      CLOSE c1
      DEALLOCATE c1
    --display both results and errors
    SELECT * FROM #tmp
    SELECT * FROM @ErrorRecap

    ...