If i have to grant access to Database using T-SQL and also verify if user already exist in SQL ,
If user don't exist then create account first and then grant access to database.
If user exist, just grant access to database.
I only create users in SQL. Not in Windows.
What will be by T-SQL Query to achieve above. ?
Try to create your login first, and the your user. This code first checks where all your users are assigned to which databases. Afterwards it checks if there is a login created and then it checks if the user exists. It is also set dynamically to you can just enter a DBName.
Example
---Get information on which users has access to my datase
set nocount on
declare #permission table (
Database_Name sysname,
User_Role_Name sysname
)
declare #dbs table (dbname sysname)
declare #Next sysname
insert into #dbs
select name from sys.databases order by name
select top 1 #Next = dbname from #dbs
while (##rowcount<>0)
begin
insert into #permission
exec('use [' + #Next + ']
SELECT ''' + #Next + ''', a.name as ''User or Role Name''
FROM [' + #Next + '].sys.database_principals a
left join [' + #Next + '].sys.database_permissions d on a.principal_id = d.grantee_principal_id
order by a.name, d.class_desc')
delete #dbs where dbname = #Next
select top 1 #Next = dbname from #dbs
end
set nocount off
--Declare my Variables
Declare #DBName VARCHAR(30)
DECLARE #IsWindowsUser int = 0
DECLARE #UserName nvarchar(50) = 'hestt4545tt'
DECLARE #PassWord nvarchar(50) = 'hest123123'
DECLARE #LoginExists int
DECLARE #UserExists int
DECLARE #LoginSQL nvarchar(MAX)
DECLARE #UserSQL nvarchar(MAX)
DECLARE #MultiDatabase nvarchar(max) ='LegOgSpass,LoadConfiguration'
--SET #DBName = 'LegOgSpass'
DECLARE myCursor CURSOR FOR
select [value] from string_split(#MultiDatabase,',')
OPEN myCursor
FETCH NEXT FROM myCursor INTO #DBName
WHILE ##FETCH_STATUS = 0
BEGIN
exec('USE '+ #DBName)
IF #IsWindowsUser = 0
BEGIN
/* Users are typically mapped to logins, as OP's question implies,
so make sure an appropriate login exists. */
SET #LoginExists = (Select count(principal_id) FROM sys.server_principals WHERE name = #UserName)
---Check if login exists - else create it
IF #LoginExists = 0
BEGIN
/* Syntax for SQL server login. See BOL for domain logins, etc. */
SET #LoginSQL = 'USE ' +#DBName + ' CREATE LOGIN '+#UserName +' WITH PASSWORD = '''+#PassWord+''''
PRINT 'Login doesnt exists'
EXEC (#LoginSQL)
PRINT 'Therefore i make a new login now'
SET #LoginExists = (Select count(principal_id) FROM sys.server_principals WHERE name = #UserName)
IF #LoginExists = 1
PRINT 'Login is now created and exists'
BEGIN
SET #UserExists = (SELECT count(principal_id) FROM sys.database_principals WHERE name = #UserName)
IF #UserExists =0
PRINT 'User doesnt exists'
BEGIN
SET #UserSQL = 'USE ' +#DBName+ ' CREATE USER ' +#UserName +' FOR LOGIN '+#UserName
EXEC (#UserSQL)
PRINT 'User is now created'
END
END
END
ELSE
BEGIN
SET #UserExists = (select COUNT(distinct User_Role_Name) from #permission where User_Role_Name =#UserName and Database_Name = #DBName)
IF #UserExists =0
BEGIN
PRINT 'Login already exists - go create user for access to database'
SET #UserSQL = 'USE ' +#DBName+ ' CREATE USER ' +#UserName +' FOR LOGIN '+#UserName
EXEC (#UserSQL)
PRINT 'User is now created'
END
END
END
ELSE
BEGIN
SET #LoginExists = (Select count(principal_id) FROM sys.server_principals WHERE name = REPLACE(REPLACE(#UserName,'[',''),']',''))
---Check if login exists - else create it
IF #LoginExists = 0
BEGIN
/* Syntax for SQL server login. See BOL for domain logins, etc. */
SET #LoginSQL = 'USE ' +#DBName + ' CREATE LOGIN '+#UserName +' FROM WINDOWS'
PRINT 'Windows Login doesnt exists'
EXEC (#LoginSQL)
PRINT 'Therefore i make a new window login now'
SET #LoginExists = (Select count(principal_id) FROM sys.server_principals WHERE name = #UserName)
IF #LoginExists = 1
PRINT 'Windows Login is now created and exists'
BEGIN
SET #UserExists = (SELECT count(principal_id) FROM sys.database_principals WHERE name = #UserName)
IF #UserExists =0
PRINT 'User doesnt exists'
BEGIN
SET #UserSQL = 'USE ' +#DBName+ ' CREATE USER ' +#UserName +' FOR LOGIN '+#UserName
EXEC (#UserSQL)
PRINT 'User is now created'
END
END
END
ELSE
BEGIN
SET #UserExists = (select COUNT(distinct User_Role_Name) from #permission where User_Role_Name =REPLACE(REPLACE(#UserName,'[',''),']','') and Database_Name = #DBName)
IF #UserExists =0
BEGIN
PRINT 'Window Login already exists - go create user for access to database'
SET #UserSQL = 'USE ' +#DBName+ ' CREATE USER ' +#UserName +' FOR LOGIN '+#UserName
EXEC (#UserSQL)
PRINT 'User is now created'
END
END
END
FETCH NEXT FROM myCursor INTO #DBName
--Ending cursor
END
CLOSE myCursor
DEALLOCATE myCursor
Related
I have a script like this:
declare #username nvarchar(255)
declare #Alterstatement nvarchar(2000)
declare #userloginname nvarchar(255)
declare #InsertIntoHistory nvarchar(2000)
declare getusername cursor
for
select name from [SysAdmin].[dbo].[DisabledAccount]
where name in (select name from sys.server_principals)
open getusername
Fetch next from getusername into #username
while ##FETCH_STATUS=0
begin
set #userloginname = '[' + #username + ']'`
set #Alterstatement = 'Alter Login' +#userloginname +'Disable'
set #InsertIntoHistory = 'Insert into DisabledAccountHistory (DisabledName,ServerName) values('''
+ #username + ''','''+ ##servername +''')'
exec(#alterstatement)
exec(#InsertIntoHistory)
Fetch next from getusername
into #username
end
close getusername
deallocate getusername
I'm using this script to disable some users and insert into a history table. But when I run this, some problem shows up. For example when I have only one user that I need to disable, it will run 3 times and insert 3 rows into the history table. How can I ask it just run 1 time for each user?
I would get rid of the cursor completely as it isn't needed here. You can still disable all the logins and insert the data into your history table.
declare #SQL nvarchar(max) = ''
select #SQL = #SQL + 'ALTER LOGIN ' + QUOTENAME(name) + ' DISABLE;'
from [SysAdmin].[dbo].[DisabledAccount]
where name in (select name from sys.server_principals)
group by name
exec sp_executesql #SQL
Insert into DisabledAccountHistory
(
DisabledName
, ServerName
)
select name
, ##servername
from [SysAdmin].[dbo].[DisabledAccount]
where name in (select name from sys.server_principals)
group by name
I've got a small issue with delphi/sql server. I have a SP
GO
/****** Object: StoredProcedure [dbo].[sp_adaugaUser] Script Date: 6/30/2014 12:33:52 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
ALTER PROCEDURE [dbo].[sp_adaugaUser]
-- Add the parameters for the stored procedure here
#User varchar(50),
#Password varchar(32)--,
-- #errMesaj varchar(50)
AS
BEGIN
declare #sUser varchar(50),
#sPassword varchar(32),
#errMesaj varchar(100),
#exists bit,
#exists2 bit;
set #sUser = LTRIM(RTRIM(#User))
set #sPassword = LTRIM(RTRIM(#Password))
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
select #exists = COUNT(*) from sys.server_principals where name = #sUser
select #exists2 = COUNT(*) from sys.database_principals where name = #sUser
-- Insert statements for procedure here
if #exists = 1 begin
if #exists2 = 1 set #errMesaj = 1 --'Userul deja exista'
else begin
exec ('CREATE USER [' + #sUser + '] FOR LOGIN [' + #sUser + ']')
set #errMesaj = 2 --'S-a creat userul pentru login deja existent'
end
end
else begin
exec(' CREATE LOGIN [' + #sUser + '] WITH PASSWORD = ''' +#sPassword + '''
CREATE USER [' + #sUser + '] FOR LOGIN [' + #sUser+']')
set #errMesaj = 3 --'S-a creat user si login'
end
RETURN #errMesaj
END
This SP add a login and a user into a server/database... and returns a message based on what it has done.
In delphi I've got a TADOStoredProcedure that has 3 parameters :
1 : #User - ftString , pdInput
2 : #Password - ftString , pdInput
1 : #errMesaj - ftString , pdReturnValue
I call the TADOStoredProcedure like this :
procedure TdataModule1.AdaugaUser(user, password : string ); // procedura ce apeleaza o SP din BD pentru adaugarea de useri
begin
sp_adaugaUser.Parameters.ParamByName('#User').Value := user;
sp_adaugaUser.Parameters.ParamByName('#Password').Value := password;
sp_adaugaUser.Prepared := true ;
try
sp_adaugaUser.ExecProc;
finally
sp_adaugaUser.Prepared := false ;
sp_vizualizare_useri.Close;
sp_vizualizare_useri.Open;
test := sp_adaugaUser.Parameters.ParamByName('#errMesaj').Value;
end;
end;
but for some reason when I debug the value of test is always null, why?
Error :
If you want to use the parameter #errMesaj as described you will have to define it with OUTPUT.
ALTER PROCEDURE [dbo].[sp_adaugaUser]
-- Add the parameters for the stored procedure here
#User varchar(50),
#Password varchar(32),
#errMesaj varchar(100) OUTPUT
AS
The RESULT value of SQLServer procedure is limited to an integer Return Data from a Stored Procedure
An example to show the different possibilies could look like this:
Alter PROCEDURE [dbo].[sp_adaugaUser]
-- Add the parameters for the stored procedure here
#User varchar(50),
#Password varchar(32),
#errMesaj varchar(100) OUTPUT
AS
BEGIN
declare #sUser varchar(50),
#sPassword varchar(32),
#ReturnCode int,
#exists bit,
#exists2 bit;
set #sUser = LTRIM(RTRIM(#User))
set #sPassword = LTRIM(RTRIM(#Password))
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
select #exists = COUNT(*) from sys.server_principals where name = #sUser
select #exists2 = COUNT(*) from sys.database_principals where name = #sUser
-- Insert statements for procedure here
if #exists = 1 begin
if #exists2 = 1
begin
set #errMesaj = 'Userul deja exista'
set #ReturnCode = 1
end
else begin
exec ('CREATE USER [' + #sUser + '] FOR LOGIN [' + #sUser + ']')
set #errMesaj = 'S-a creat userul pentru login deja existent'
set #ReturnCode = 2
end
end
else begin
exec(' CREATE LOGIN [' + #sUser + '] WITH PASSWORD = ''' +#sPassword + '''
CREATE USER [' + #sUser + '] FOR LOGIN [' + #sUser+']')
set #errMesaj = 'S-a creat user si login'
set #ReturnCode = 2
end
Return #ReturnCode
END
the minimal delphi code for a call
sp_adaugaUser.Parameters.ParamByName('#User').Value := user;
sp_adaugaUser.Parameters.ParamByName('#Password').Value := password;
sp_adaugaUser.ExecProc;
Showmessage(sp_adaugaUser.Parameters.ParamByName('#errMesaj').Value);
Showmessage(IntToStr(sp_adaugaUser.Parameters.ParamByName('#RETURN_VALUE').Value));
using a TAdoStoredProc for sp_adaugaUser your parameters should look like this
the error you are getting is because in
test := sp_adaugaUser.Parameters.ParamByName('#errMesaj').Value; the value is NULL which can't be converted to a string.
I need to test if a table exists in a linked server, where linked server is a parameter (it has to be), that's why I'm using exec method. I tried many ways but I didn't succeed.
Declare #LinkedServerName varchar(50)
Declare #DS varchar(50)
Declare #username varchar(50)
Declare #pswd varchar(12)
Declare #TableExists int
Set #DS = 'test\TestDB'
Set #LinkedServerName = 'LinkedServerAutoAddDrop'
Set #username = 'ua'
Set #pswd = 'pass'
Set #TableExists = 0
if not exists(select * from sys.servers where name = #LinkedServerName)
BEGIN
EXEC sp_addlinkedserver
#server=#LinkedServerName,
#srvproduct='',
#provider='SQLNCLI',
#datasrc=#DS
EXEC sp_addlinkedsrvlogin #LinkedServerName, N'false', NULL, #username, #pswd
exec sp_serveroption #server=#LinkedServerName, #optname='rpc', #optvalue='TRUE'
exec sp_serveroption #server=#LinkedServerName, #optname='rpc out', #optvalue='TRUE'
END
exec('IF (EXISTS (SELECT * FROM OPENQUERY([' + #LinkedServerName + '], ''select * from LinkedDB.INFORMATION_SCHEMA.TABLES Where TABLE_NAME = ''''TableName'''''')))
BEGIN
exec (''Set ' + #TableExists + ' = 1'')
END')
IF (#TableExists = 1)
BEGIN
exec('Insert Into ...')
END
I personally would use sp_executesql along with an output parameter for this:
DECLARE #SQL NVARCHAR(MAX) = ''
DECLARE #TableExists BIT;
SET #SQL = 'SELECT #TableExists = CASE WHEN TableExists = 0 THEN 0 ELSE 1 END
FROM OPENQUERY(' + QUOTENAME(#LinkedServerName)
+ ', ''SELECT TableExists = COUNT(*)
FROM LinkedDB.INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = ''''TableName'''''');';
EXECUTE sp_executesql #SQL, N'#TableExists BIT OUTPUT', #TableExists OUT;
IF (#TableExists = 1)
BEGIN
-- DO SOMETHING
END;
TO Check If Column Exist Or Not I Use following:
If Returns 1 then COLUMN EXIST Else If 0 then COLUMN DOSE NOT EXIST
If Database On same Server then Provide #ServerName as Empty Field ('')
CREATE PROCEDURE [dbo].[udsp_CheckIfColumExist](#DBName Varchar(1000),#ColName Varchar(1000),#TableName Varchar(1000),#ServerName Varchar(1000))AS
DECLARE #SqlStr VARCHAR(MAX) = ''
IF #ServerName <> ''
SET #ServerName = '['+#ServerName+'].'
SET #SqlStr ='SELECT COUNT(1) IsExist FROM '+ #ServerName + #DBName+'.sys.columns
c join '+ #ServerName + #DBName +'.sys.tables t on t.OBJECT_ID = c.OBJECT_ID
WHERE c.name = N'''+#ColName +''' AND t.name = N''' +#TableName +''''
EXEC(#SqlStr)
If you want to perform same check on table remove column part from query.
What I'm trying to accomplish is to remove any extra users/schemas (anything listed in NOT IN I want to keep). I can't blanket remove the users in case they are attached to any schemas by the same name (some are like that, some aren't), so I'm trying to check to see if the schema I want to remove exists, if it does, then I want to remove it. I want to do the same for any users attached to databases using the same logic.
My problem is when I run the script, it finds the users/schemas I want to remove but it throws an error saying "Invalid column name 'USERNAME HERE'.
Any ideas?
declare #sql nvarchar(max)
set #sql = ''
SELECT #sql = #sql+
'
IF EXISTS (SELECT NAME FROM sys.schemas WHERE NAME = "'+ name +'" )
BEGIN
DROP SCHEMA "'+ name +'"
END
IF EXISTS (SELECT NAME FROM dbo.sysusers WHERE NAME = "'+ name +'" )
BEGIN
DROP USER "'+ name +'"
END
'
FROM
dbo.sysusers
WHERE
name NOT IN('dbo','guest','INFORMATION_SCHEMA','sys','public')
AND LEFT(name,3) <> 'db_'
order by
name
execute ( #sql )
--print (#sql)
For anyone curious I got this working using a cursor.
DECLARE #UserName varchar(256)
DECLARE #sqlSchema varchar(100)
DECLARE #sqlUser varchar(100)
DECLARE csrUser CURSOR FOR
SELECT [name] FROM sys.database_principals WHERE name
NOT IN('dbo','guest','INFORMATION_SCHEMA','sys','public') AND LEFT(name,3) <> 'db_'
ORDER BY [name]
OPEN csrUser
FETCH NEXT FROM csrUser INTO #UserName
WHILE ##FETCH_STATUS <> -1
BEGIN
IF EXISTS(SELECT NAME FROM sys.schemas WHERE NAME = #userName )
BEGIN
set #sqlSchema = 'drop schema "' + #userName + '"'
print #sqlSchema
--exec (#sqlSchema)
WAITFOR DELAY '00:00:05'
END
set #sqlUser = 'drop user "' + #userName + '"'
print #sqlUser
--exec (#sqlUser)
FETCH NEXT FROM csrUser INTO #UserName
END
CLOSE csrUser
DEALLOCATE csrUser
I had to include the WAITFOR DELAY because whenever it tried to drop the user, SQL was still saying it was associated with a schema.
Are you using " (Double quotation) or '' (two single quotations) for escaping the quotation mark? It looks if you're using the double quotation mark which is not right.
It should be:
declare #sql nvarchar(max)
set #sql = ''
SELECT #sql = #sql+
'
IF EXISTS (SELECT NAME FROM sys.schemas WHERE NAME = '''+ name +''' )
BEGIN
DROP SCHEMA '''+ name +'''
END
IF EXISTS (SELECT NAME FROM dbo.sysusers WHERE NAME = '''+ name +''' )
BEGIN
DROP USER '''+ name +'''
END
'
FROM
dbo.sysusers
WHERE
name NOT IN('dbo','guest','INFORMATION_SCHEMA','sys','public')
AND LEFT(name,3) <> 'db_'
order by
name
--execute ( #sql )
print (#sql)
After performing a database restore, I want to run a dynamic script to fix ophaned users. My script below loops through all users that are displayed after executing sp_change_users_login 'report' and applys an "alter user [username] with login = [username]" statement to fix SID conflicts. I'm getting an "incorrect syntax error on line 15" and can't figure out why...help..
DECLARE #Username varchar(100), #cmd varchar(100)
DECLARE userLogin_cursor CURSOR FAST_FORWARD
FOR
SELECT UserName = name FROM sysusers
WHERE issqluser = 1 and (sid IS NOT NULL AND sid <> 0×0)
AND suser_sname(sid) IS NULL
ORDER BY name
FOR READ ONLY
OPEN userLogin_cursor
FETCH NEXT FROM userLogin_cursor INTO #Username
WHILE ##fetch_status = 0
BEGIN
SET #cmd = ‘ALTER USER ‘+#username+‘ WITH LOGIN ‘+#username
EXECUTE(#cmd)
FETCH NEXT FROM userLogin_cursor INTO #Username
END
CLOSE userLogin_cursor
DEALLOCATE userLogin_cursor
Orphaned users can be fixed by using the [dbo].[sp_change_users_login] stored procedure.
Loop through all your users and execute the procedure
Good Luck
DECLARE #UserCount INT
DECLARE #UserCurr INT
DECLARE #userName VARCHAR(100)
DECLARE #vsql NVARCHAR(4000)
DECLARE #Users TABLE(
id INT IDENTITY(1,1) PRIMARY KEY NOT NULL,
userName VARCHAR(100))
INSERT INTO #Users(UserName)
SELECT [name] FROM
--
master.[dbo].sysUsers -- SQL 2008 & SQL 2005
--master.dbo.sysxlogins -- SQL 2000
SELECT #UserCount = max([id]) FROM #Users
SET #UserCurr = 1
WHILE (#UserCurr <= #UserCount)
BEGIN
SELECT #userName=userName FROM #Users WHERE [id] =#UserCurr
SET #vsql = '[dbo].[sp_change_users_login] ''AUTO_FIX'',''' + #userName + ''''
-- EXEC(#vsql)
PRINT #vsql
SET #UserCurr = #UserCurr + 1
END
DECLARE #Username VARCHAR(100),
#cmd VARCHAR(100)
DECLARE userlogin_cursor CURSOR FAST_FORWARD FOR
SELECT username = name
FROM sysusers
WHERE issqluser = 1
AND (sid IS NOT NULL
AND sid <> 0x01)
AND Suser_sname(sid) IS NULL
ORDER BY name
FOR READ ONLY
OPEN userlogin_cursor
FETCH NEXT FROM userlogin_cursor INTO #Username
WHILE ##FETCH_STATUS = 0
BEGIN
SET #cmd = 'ALTER USER [' + #username + '] WITH LOGIN = [' + #username + ']'
EXECUTE(#cmd)
FETCH NEXT FROM userlogin_cursor INTO #Username
END
CLOSE userlogin_cursor
DEALLOCATE userlogin_cursor
I've used a similar approach, wrapping the code in a stored procedure:
USE [master]
GO
CREATE PROCEDURE [sp_AutoFixAllUsers]
AS
BEGIN
DECLARE #AutoFixCommand NVARCHAR(MAX)
SET #AutoFixCommand = ''
SELECT --dp.[name], dp.[sid] AS [DatabaseSID], sp.[sid] AS [ServerSID],
#AutoFixCommand = #AutoFixCommand + ' '
+ 'EXEC sp_change_users_login ''Auto_Fix'', ''' + dp.[name] + ''';'-- AS [AutoFixCommand]
FROM sys.database_principals dp
INNER JOIN sys.server_principals sp
ON dp.[name] = sp.[name] COLLATE DATABASE_DEFAULT
WHERE dp.[type_desc] IN ('SQL_USER', 'WINDOWS_USER', 'WINDOWS_GROUP')
AND sp.[type_desc] IN ('SQL_LOGIN', 'WINDOWS_LOGIN', 'WINDOWS_GROUP')
AND dp.[sid] <> sp.[sid]
IF (#AutoFixCommand <> '')
BEGIN
PRINT 'Fixing users in database: ' + DB_NAME()
PRINT #AutoFixCommand
EXEC(#AutoFixCommand)
PRINT ''
END
END
GO
I then used the sys.sp_MS_marksystemobject stored procedure to make my stored procedure available in all user databases (allowing it to operate on local objects)
EXEC sys.sp_MS_marksystemobject 'sp_AutoFixAllUsers'
You can then run it as follows:
EXEC [MyDB].[dbo].[sp_AutoFixAllUsers]
Or for every database using sp_msforeachdb:
EXEC sp_msforeachdb '[?].[dbo].[sp_AutoFixAllUsers]'