Grant EXECUTE Permissions on all Stored Procedures to a Single User

I have to run similar code on a regular basis, so I thought I would share it with everyone.

Basically, it grants access on every stored procedure that meets a certain naming pattern to a single user.

-- I've updated this with Aaron Bertrand's suggestions from the comments.
-- Thanks to Aaron for helping make this better!
DECLARE @sql AS NVARCHAR(MAX);
DECLARE @newline AS NVARCHAR(2);
DECLARE @user_name AS NVARCHAR(100);
DECLARE @sproc_name_pattern AS NVARCHAR(10);

SET @sql = N''
SET @newline = NCHAR(13) + NCHAR(10);
SET @user_name = N'jeremiah';
-- escaping _ prevents it from matching any single character
-- including the wildcard makes this much more portable between DBs
SET @sproc_name_pattern = N'sproc[_]%';

-- using QUOTENAME will properly escape any object names with spaces
-- or other funky characters
SELECT @sql = @sql
              + N'GRANT EXECUTE ON '
              + QUOTENAME(OBJECT_SCHEMA_NAME([object_id])) + '.'
              + QUOTENAME([name])
              + N' TO '
              + QUOTENAME(@user_name)
              + N';'
              + @newline + @newline
  FROM sys.procedures
 WHERE [name] LIKE @sproc_name_pattern;

-- this is my version of debug code, I usually run it once with the PRINT intact
-- before I actually use sp_executesql
--PRINT @sql;

EXEC sp_executesql @sql;

Comments

9 Comments so far. Leave a comment below.
  1. Three suggestions:

    (1) escape _ (otherwise it is treated as “any single character”)
    (2) store the whole pattern in the string (that way if you move this to a procedure you don’t have to change the procedure to support LIKE ‘%[_]foo’ etc.)
    (3) QUOTENAME() object names and include schema prefix in output

    SET @sproc_name_pattern = N’sproc[_]%’;

    SELECT @sql = @sql N’GRANT EXECUTE ON ‘
    + QUOTENAME(OBJECT_SCHEMA_NAME([object_id])) + ‘.’
    + QUOTENAME([name])
    + ‘ TO ‘
    + QUOTENAME(@user_name)
    + ‘;’
    + @newline + @newline
    FROM sys.procedures
    WHERE [name] LIKE @sproc_name_pattern;

  2. Note that OBJECT_SCHEMA_NAME() requires 2005 SP2+, IIRC

  3. Very true, OBJECT_SCHEMA_NAME is a newer function. You can also use SCHEMA_NAME([schema_id]) to get the schema name on older releases of SQL Server 2005.

  4. Sorry, as I tweeted, I am always using the newer function because many catalog views and dynamic management views/functions do not include schema_id. And I’d rather use the function than write out the joins by hand. I’m lazy. And thankfully am not managing any pre-SP2 SQL Server 2005 instances.

  5. No worries, I can definitely see why you would prefer OBJECT_SCHEMA_NAME() over SCHEMA_NAME(). Special thanks to both John Keyes (twitter.com/jckeyes) and Brian Davis (twitter.com/brian78) for confirming that SCHEMA_NAME() works on SQL Server 2005 RTM and SP1.

  6. I love this trick! Here’s my version in case you’re interested:

    Declare @schema_owner varchar(20);
    Set @schema_owner = ‘dbo’;

    Select [name] As ‘storedProcedure’
    , ‘Grant Execute On ‘ + @schema_owner + ‘.’ + [name]
    + ‘ To [insertDatabaseRoleHere];’ As ‘sqlCode’
    From sys.objects With (NoLock)
    Where [name] Not In (
    Select o.name
    From sys.database_permissions p With (NoLock)
    Inner Join sys.objects o With (NoLock)
    On p.major_id = o.object_id
    Inner Join sys.database_principals u With (NoLock)
    On u.principal_id = p.grantee_principal_id
    Where u.name = ‘[insertDatabaseRoleHere]‘
    )
    And [type] = ‘P’;

    There’s a couple of differences between our scripts. Your script is used to set up a brand new user, and mine is to check for missing permissions for an existing database role. Also, you automatically execute, and mine you have to copy/paste/execute. But overall, pretty much the same thing, just different ways to get there. :)

  7. CREATE ROLE db_executor
    GRANT EXECUTE TO db_executor
    EXEC sp_addrolemember ‘db_executor’, ‘<>’

    This would work if you’re looking to do it for all stored procedures.

  8. My version is here

    http://wiki.lessthandot.com/index.php/Grant_Execute_Permissions_For_All_Stored_Procedures_To_A_User

    –Grab all the procedures for the current DB
    SELECT IDENTITY(INT,1,1) AS ID,
    SPECIFIC_NAME
    INTO #Procedurelist
    FROM INFORMATION_SCHEMA.ROUTINES –Only Procs
    WHERE OBJECTPROPERTY(OBJECT_ID(SPECIFIC_NAME),’IsMSShipped’) =0
    AND ROUTINE_TYPE=’PROCEDURE’
    ORDER BY SPECIFIC_NAME

    DECLARE
    @Loopid INT,
    @MaxId INT,
    @UserName VARCHAR(50)

    –This is the user that will get the execute permissions
    SELECT @UserName = ‘SomeUser’

    –Grab start and end values for the loop
    SELECT @Loopid = 1,
    @MaxId = MAX(ID)
    FROM #Procedurelist

    DECLARE
    @SQL VARCHAR(500),
    @ProcName VARCHAR(400)

    –This is where the loop starts
    WHILE @Loopid <= @MaxId BEGIN

    –grab the procedure name
    SELECT @ProcName = SPECIFIC_NAME
    FROM #Procedurelist
    WHERE ID = @Loopid

    –construct the statement
    SELECT @SQL = ‘GRANT EXECUTE ON ‘ + @ProcName + ‘ TO ‘ + @UserName
    PRINT (@SQL) –change PRINT to EXECUTE if you want it to run automatically

    –increment counter
    SET @Loopid = @Loopid + 1
    END

    –clean up
    DROP TABLE #Procedurelist

  9. Thanks Jeremiah. Very simple solution that saves alot of time and works without looping.

Add Your Comments

Disclaimer
Your email is never published nor shared.
Required
Required
Tips

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <ol> <ul> <li> <strong> <p>

Ready?

This site is protected with Urban Giraffe's plugin 'HTML Purified' and Edward Z. Yang's Powered by HTML Purifier. 230 items have been purified.