Grant Server roles SQL server 2008R2 - sql-server

I have a tool which updates my sql table 'eptrack' with the following information
Server, Instance, userid, access, startdate and expirydate.
every time this table is updated a trigger will initiate a job which in turn connects to the respective server/Instance and grant the requested server roles.
I am able to grant the role via the following query.
exec sp_addsrvrolemember'na\admin_Test1', 'sysadmin'
However when i try to pick this info from the table via the below query,I get an error.
EXEC sp_addrolemember '(select userid from eptrack)' , '(select access from eptrack)'
Could I get a help for a query on granting the server role picked from the table for the userid in the same table

According to sp_addrolemember,this accepts variables as well
-- Syntax for SQL Server and Azure SQL Database
sp_addrolemember [ #rolename = ] 'role',
[ #membername = ] 'security_account'
so you can try something like below
declare #rolename sysname,
#membername sysname
select #rolename='db_Datareader',#membername='test'
EXEC sp_addrolemember #rolename,#membername
The above select can be from your table,if there are multiple results from select this will not work as expected, you may want to have a method which tracks/get only one row at a time

You should use a cursor for going through your table, get 1 row at a time, assign 2 variables and pass them to sp_addsrvrolemember like this:
declare #eptrack table (userid sysname, access sysname);
insert into #eptrack values ('na\admin_Test1', 'sysadmin');
declare #rolename sysname, #membername sysname;
select #rolename = access, #membername = userid
from #eptrack;
exec sp_addsrvrolemember #membername, #rolename;

Thank you for the assistance. I tried the above query as mentioned below
declare #rolename sysname,
#membername sysname
select #rolename=(select access from eptrack),#membername= (select userid from eptrack)
EXEC sp_addrolemember #rolename,#membername
I see an error the user id does not exist. I just inserted the information in the table and executed the query after that.

This worked, thank you. however we are entering the userid and access manually and we need those info picked from the table
declare #eptrack table (userid sysname, access sysname);
insert into #eptrack values ((select userid from eptrack), (select access from eptrack));
declare #rolename sysname, #membername sysname;
select #rolename = access, #membername = userid
from #eptrack;
exec sp_addsrvrolemember #membername, #rolename;
I tried the above one and see an error user id is not a valid login.
wanted to check if I am entering the select command right?
The table will have new rows inserted frequently and the query needs to pick the userid and access from the table every time a new value is inserted.

Related

Programmatically give access to databases

Scenario: Instructor of a database course wants to do the following for each of 100 students every semester: (a) create login from windows, (b) create database for each student where they are db_owner, (c) each student has read access to a database.
Here is the script I have so far:
DECLARE #DBname varchar(10) = 'aa1833'
DECLARE #Lname varchar(20) = 'STUDENTS'+'\'+#DBname
DECLARE #CreateDB varchar(max) = 'CREATE DATABASE '+#DBname
EXEC(#CreateDB)
DECLARE #CreateLogin varchar(max) = 'CREATE LOGIN ['+#Lname+ '] FROM WINDOWS'
EXEC(#CreateLogin)
USE sample_database
EXEC sp_addrolemember 'db_datareader', #Lname
EXEC sp_droprolemember 'db_owner', #Lname
DECLARE #dbRights varchar(max) = 'USE '+#DBname
EXEC(#dbRights)
EXEC sp_addrolemember 'db_owner', #Lname
I would appreciate help with following issues:
The above script is able to create logins and user's database. However, access rights (to individual database and sample database) are incorrect.
To manage server space, I would like to delete student accounts and their databases at the end of each semester. Can we have database names such as students\f21\001\aa1833?
Any other comments to improve this set up (students cannot access others' work and edit contents) would be appreciated.
SQL Server 15
The database context reverts back to the outer context (sample_database) after the dynamic SQL USE statement runs so the subsequent sp_addrolemember runs in sample_database instead of aa1833 as intended.
Execute USE and sp_addrolemember in the same dynamic SQL batch to avoid the issue:
DECLARE #dbRights varchar(max) = 'USE ' + QUOTENAME(#DBname) + N';EXEC sp_addrolemember ''db_owner'', #Lname';
sp_executesql #dbRights, N'#Lname sysname', #Lname = #Lname;

is there a way i can get an alert whenever a table gets records in sql server

i have a table in SQl server which occasionally gets data from a linked server, and than i have to do activities on it .
but the problem is there is no way to check if the data is inserted in table (table is always truncated after performing the activity so next time when data is pushed table is already empty) i manually check daily for data if it is inserted or not .
what i want is to get auto alert on my email (i already have db_mail configured and working) whenever the data is pushed in a table .
i have sa admin and complete privileges on Database and also on Windows server 2012 R2
You can do this with a trigger but you will have to do some preparations with privileges so the executor (the login that's inserting the records on your tracking table) can send email correctly:
CREATE TRIGGER dbo.TrackingTableNameAfterInsert ON TrackingTable
AFTER INSERT
AS
BEGIN
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'YourConfiguredProfile',
#recipients = 'youremail#mail.com',
#subject = 'Records were inserted on TrackingTable',
#body = ''
END
You might want to encapsulate the email sending on an SP and configure it's permissions there.
In regards to the following:
...table is always truncated after performing the activity so next time
when data is pushed table is already empty...
You can create a historical table and use a trigger to also insert inserted records on this table, so the TRUNCATE or DROP of the original one won't affect the copied records.
CREATE TABLE TrackingTableMirror (
/*Same columns and types*/
InsertedDate DATETIME DEFAULT GETDATE())
GO
CREATE TRIGGER dbo.TrackingTableInsertMirror ON TrackingTable
AFTER INSERT
AS
BEGIN
INSERT INTO TrackingTableMirror (
/*Column list*/)
SELECT
/*Column list*/
FROM
inserted AS I
END
This way you can check all records on this mirrored table and not the volatile one (and avoid all the email sending).
1) Create Profile and Account
You need to create a profile and account using the Configure Database Mail Wizard which can be accessed from the Configure Database Mail context menu of the Database Mail node in Management Node. This wizard is used to manage accounts, profiles, and Database Mail global settings.
2) Run Query
sp_CONFIGURE 'show advanced', 1
GO
RECONFIGURE
GO
sp_CONFIGURE 'Database Mail XPs', 1
GO
RECONFIGURE
GO
3)
USE msdb
GO
EXEC sp_send_dbmail #profile_name='yourprofilename',
#recipients='test#Example.com',
#subject='Test message',
#body='This is the body of the test message.
Congrates Database Mail Received By you Successfully.'
through the table
DECLARE #email_id NVARCHAR(450), #id BIGINT, #max_id BIGINT, #query NVARCHAR(1000)
SELECT #id=MIN(id), #max_id=MAX(id) FROM [email_adresses]
WHILE #id<=#max_id
BEGIN
SELECT #email_id=email_id
FROM [email_adresses]
set #query='sp_send_dbmail #profile_name=''yourprofilename'',
#recipients='''+#email_id+''',
#subject=''Test message'',
#body=''This is the body of the test message.
Congrates Database Mail Received By you Successfully.'''
EXEC #query
SELECT #id=MIN(id) FROM [email_adresses] where id>#id
END
4) Trigger Code
CREATE TRIGGER [dbo].[Customer_INSERT_Notification]
ON [dbo].[Customers]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #CustomerId INT
SELECT #CustomerId = INSERTED.CustomerId
FROM INSERTED
declare #body varchar(500) = 'Customer with ID: ' + CAST(#CustomerId AS VARCHAR(5)) + ' inserted.'
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'Email_Profile'
,#recipients = 'recipient#gmail.com'
,#subject = 'New Customer Record'
,#body = #body
,#importance ='HIGH'
END
I refer this link.

SQL create user login not working from one database for other database

I have two databases on a same server, db1 and db2.
I have one table on db1 named table table1, and table2 inside second database db2
users have login for db1 but not for db2.
My application insert records in table1 and I have to insert same records in table2 on second database.
Now since users don't have access to that database, I am trying to first create user logins.
but executing stored procedure, but it don't create user login. My stored procedure is in db1.
alter procedure CreateUserLogin #userid char(35)
as
declare #s varchar(100)
IF NOT EXISTS (SELECT * FROM db2.sys.database_principals WHERE name = #userid)
BEGIN
set #s='use db2 CREATE USER '+ltrim(rtrim(#userid))+' FROM LOGIN '+ltrim(rtrim(#userid))+''
set #s=#s + 'Exec sp_addrolemember Role1,'+ ltrim(rtrim(#userid))
exec (#s)
END;
After adding + CHAR(13)
set #s='USE [db2]'+ CHAR(13)
set #s=#s+' CREATE USER '+ltrim(rtrim(#userid))+' FROM LOGIN '+ltrim(rtrim(#userid))+''
set #s=#s + ' Exec sp_addrolemember role1,'+ ltrim(rtrim(#userid))
didn't know this could be a problem.

sys.database_principals is not executed in current database if called from sp procedure (stored in master)

I would like to print out database users of an actual database in a SP procedure (see the code of sp_PrintUsers below), however, for some reason it print out database users of master. It seems that it is a general behavior of SP procedure for all database-level views despite the fact that any database-level SQL statement is executed in the actual database. If we print out the DB_NAME that it is clearly not master, so what is wrong?
Is there any workaround?
use [master]
go
create procedure sp_PrintUsers
as
begin
SELECT DB_NAME() AS DataBaseName
select name from sys.database_principals;
end
go
use [actual_database]
go
exec sp_PrintUsers
Try executing the select dynamically as in:
EXEC('select name from sys.database_principals;');
If that does not help build the query to reference the catalog view with a three part name.
Try this :
use [master]
go
create procedure sp_PrintUsers
as
begin
declare #dbname varchar(30) = DB_NAME()
EXEC ('select name from ' + #dbname + '.sys.database_principals');
end
go
use [actual_database]
go
exec sp_PrintUsers

Change the roles of multiple security accounts

I have many security accounts on the sql database and i want to remove/add roles to them based on a simple string comparison.
Basically i want to list all
accounts
Filter out accounts that DON'T start
with "MyDomain\"
Remove role A.
Add role B.
What i found out by now is that i use sp_helprolemember to list all the accounts and sp_addrolemember and sp_droprolemember. My problem is that i dont know how to "get" the output from sp_helprolemember and work with it.
My first attemt at a soltuion based of feedback.
DROP TABLE [dbo].[XTemp]
create table XTemp(DbRole sysname,MemberName sysname,MemberSID varbinary(85) )
insert XTemp exec sp_helprolemember
select * from XTemp
I made a permanent table to make it simpler to test and debug.
SELECT [DbRole]
,[MemberName]
,[MemberSID]
FROM [ARTICLE].[dbo].[XTemp]
WHERE MemberName like Domain\%'
exec sp_addrolemember 'OldRole MemberName
Assuming that you're using SQL 2005 or later, and executing sp_helprolemember without parameters, this is the query that sp_helprolemember runs (extracted using sp_helptext):
select DbRole = g.name, MemberName = u.name, MemberSID = u.sid
from sys.database_principals u, sys.database_principals g, sys.database_role_members m
where g.principal_id = m.role_principal_id
and u.principal_id = m.member_principal_id
order by 1, 2
This should enable you to collect the information you need into a temp table.
If you'd rather stick to documented behaviour, you can store the output of the SP into a temp table:
create table #t
(DbRole sysname,
MemberName sysname,
MemberSID varbinary(85)
)
insert #t
exec sp_helprolemember
select * from #t
EDIT
There are two ways to use this data to amend your system. One is using a cursor:
DECLARE #memberName sysname
DECLARE curMember CURSOR fast_forward FOR
SELECT MemberName
FROM #t
WHERE MemberName LIKE 'Domain\%'
OPEN curMember
FETCH NEXT FROM curMember INTO #memberName
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC sp_addrolemember 'OldRole', #memberName
FETCH NEXT FROM curMember INTO #memberName
END
CLOSE curMember
DEALLOCATE curMember
The other is using dynamic SQL:
DECLARE #sql NVARCHAR(MAX),
SELECT #sql = 'EXEC sp_addrolemember ''OldRole'', ''' + MemberName + ''''
FROM #t
WHERE MemberName LIKE 'Domain\%'
EXEC sp_executesql #stmt = #sql
As you can see the dynamic SQL version is more compact but requires more effort to maintain.
Remember that after you execute either statement, the data you extracted from sp_helprolemember into a table is no longer up to date, and should probably be refreshed.
You can use Excel to generate SQL queries - I know it sounds lame but it is very simple and powerful. It is especially well-suited for tasks that have to be performed once or only from time to time.
Copy results from Management Studio to Excel.
Remove rows and columns than you don't need.
Use a formula in column B (e.g. ="EXEC sp_dropsrvrolemember '"&A1&"', 'sysadmin'") to generate queries for values stored in column A (the formula can of course reference more than one column with input data and generate really complicated queries).
Copy generated queries from Excel to Management Studio.

Resources