问题
对于DBA或者其他运维人员来说授权一个账户的相同权限给另一个账户是一个很普通的任务。但是随着服务器、数据库、应用、使用人员地增加就变得很枯燥乏味又耗时费力的工作。那么有什么容易的办法来实现这个任务吗?
当然,作为非DBA在测试甚至开发环境也会遇到这种问题,要求授予所有服务器数据库的某个权限给一个人的时候。我们是不是有什么其他办法提高效率?
解决方案
如果这个时候我们网上去搜索解决方案,大多数时候搜到的都是使用T-SQL解决方案,但是这又会产生下面几个小问题:
- 我们需要到目标服务器上执行这些脚本,有的甚至还需要部署后执行一遍。
- 不能生成这些T-SQL脚本到一个文件中。
- 重度使用的动态脚本代码冗长不方便阅读和维护。
本篇技巧的主要目的就是提供一个更好的基于PowerShell和SMO的解决方案来解决上述问题。
新的PS方法
- 在cmdlet函数中,可以接收一个SQLServer实例名称的列表以及登陆名($OldLogin),这些登陆名的权限是准备复制的。
- 对于每个实例,使用SMO Server.EnumObjectPermissions(loginName) 来获取服务对象(如登陆账号)权限并且使用Server.EnumServerPermissions(loginName) 来获取服务器级别的权限。
- 使用来查找每个存在数据库登陆账户映射$OldLogin账户关系的数据库
- 在每个映射用户的数据库中,我们可以通过,, 和 EnumObjectPermissions 来获得用户的证书、对称以及非对称秘钥、ServiceBrokers等等来检索用户的所有权限。
- 所有检索到的权限信息将被添加到一个哈希表的数组汇总,然后通过循环数组导出权限脚本到一个文件中或者运行这个脚本用来复制一个新的账户权限。
测试环境
现在我把从网上找到的脚本进行修改完善,然后如下的脚本列出来如下:
drop login [Bobby];
CREATE LOGIN [Bobby] WITH PASSWORD = 'User$To!Clon3@';
GO
EXEC sp_addsrvrolemember @loginame = 'Bobby',@rolename = 'securityadmin';
EXEC sp_addsrvrolemember @loginame = 'Bobby',@rolename = 'dbcreator';
GO
GRANT ALTER ANY SERVER ROLE TO [Bobby];
GRANT IMPERSONATE ON LOGIN::[sa] TO [Bobby];
GRANT CONTROL SERVER TO [Bobby];
GRANT ALTER ON ENDPOINT::[TSQL Default TCP] TO [Bobby];
GRANT ALTER ANY LOGIN TO [Bobby] WITH GRANT OPTION;
GRANT VIEW DEFINITION ON LOGIN::[sa] TO [Bobby];
GO
-- 2nd. Create databases
IF EXISTS(SELECT name FROM sys.databases WHERE name = 'TestA')
DROP DATABASE TestA;
CREATE DATABASE TestA;
GO
IF EXISTS(SELECT name FROM sys.databases WHERE name = 'TestB')
DROP DATABASE TestB;
CREATE DATABASE TestB;
GO
-- 3rd,create permissions or db role memberships for [Bobby]
USE TestA;
GO
CREATE USER [Bobby] FROM LOGIN [Bobby];
GO
EXEC sp_addrolemember @rolename = 'db_securityadmin',@membername = 'Bobby';
CREATE ROLE TestRoleInTestA;
GO
EXEC sp_addrolemember @rolename = 'TestRoleInTestA',@membername = 'Bobby';
GO
if object_id('dbo.t','U') is not null
drop table dbo.t;
create table dbo.t (a int identity,b varchar(30),d datetime default current_timestamp);
go
-- only SELECT ON TWO columns
GRANT SELECT on object::dbo.t (a,d) to [Bobby];
DENY UPDATE on object::dbo.t to [Bobby];
GRANT SELECT ON SCHEMA::dbo TO [Bobby];
GRANT CREATE TABLE TO [Bobby];
GRANT CREATE PROCEDURE TO [Bobby] WITH GRANT OPTION;
GO
USE TestB;
GO
CREATE USER [Bobby] FROM LOGIN [Bobby];
GO
GRANT IMPERSONATE ON USER::dbo TO [Bobby];
GO
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'S0m3Str0ng!!P4ssw0rd@';
CREATE ASYMMETRIC KEY ASymKey WITH ALGORITHM = RSA_2048;
CREATE SYMMETRIC KEY SymKey1 WITH ALGORITHM = AES_256
ENCRYPTION BY ASYMMETRIC KEY ASymKey;
CREATE CERTIFICATE TestCert
WITH SUBJECT = 'A Test Cert to Show Permission Cloning';
CREATE SYMMETRIC KEY SymKey2 WITH ALGORITHM = AES_256
ENCRYPTION BY CERTIFICATE TestCert;
GO
CREATE PROCEDURE dbo.SimpleProc
AS
BEGIN
SET NOCOUNT ON;
SELECT 'Test Procedure';
END;
GO
GRANT CONTROL ON ASYMMETRIC KEY::ASymKey TO [Bobby];
GRANT VIEW DEFINITION ON CERTIFICATE::TestCert TO [Bobby];
GRANT CONTROL ON SYMMETRIC KEY::SymKey1 TO [Bobby];
GRANT CONTROL ON SYMMETRIC KEY::SymKey2 TO [Bobby];
GRANT EXECUTE ON dbo.SimpleProc TO [Bobby];
DENY VIEW DEFINITION ON dbo.SimpleProc TO [Bobby];
GO
Use testB
go
CREATE XML SCHEMA COLLECTION XSC AS
N'<?xml version="1.0" encoding="UTF-16"?>
<xsd:schema targetNamespace="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"
xmlns ="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"
elementFormDefault="qualified"
attributeFormDefault="unqualified"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
<xsd:complexType name="StepType" mixed="true" >
<xsd:choice minOccurs="0" maxOccurs="unbounded" >
<xsd:element name="tool" type="xsd:string" />
<xsd:element name="material" type="xsd:string" />
<xsd:element name="blueprint" type="xsd:string" />
<xsd:element name="specs" type="xsd:string" />
<xsd:element name="diag" type="xsd:string" />
</xsd:choice>
</xsd:complexType>
<xsd:element name="root">
<xsd:complexType mixed="true">
<xsd:sequence>
<xsd:element name="Location" minOccurs="1" maxOccurs="unbounded">
<xsd:complexType mixed="true">
<xsd:sequence>
<xsd:element name="step" type="StepType" minOccurs="1" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="LocationID" type="xsd:integer" use="required"/>
<xsd:attribute name="SetupHours" type="xsd:decimal" use="optional"/>
<xsd:attribute name="MachineHours" type="xsd:decimal" use="optional"/>
<xsd:attribute name="LaborHours" type="xsd:decimal" use="optional"/>
<xsd:attribute name="LotSize" type="xsd:decimal" use="optional"/>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
' ;
GO
GRANT ALTER ON XML SCHEMA COLLECTION::dbo.XSC TO [BOBBY];
DENY TAKE OWNERSHIP ON XML SCHEMA COLLECTION::dbo.XSC TO [BOBBY];
GO
alter database testA set enable_broker;
use testA
create message type [//MyTest/Sample/RequestMsg] validation = well_formed_xml;
create message type [//MyTest/Sample/ReplyMsg] validation = well_formed_xml;
create contract [//Mytest/Sample/MyContract] (
[//MyTest/Sample/RequestMsg] sent by initiator,[//MyTest/Sample/ReplyMsg] sent by target);
create queue InitQu;
--create queue TargetQu;
create service [//MyTest/Sample/InitSvc] on queue InitQu;
create route ExpenseRoute with service_name= '//MyTest/Sample/InitSvc',Address='tcp://www.sqlserver.com:1234';
grant alter on Contract::[//Mytest/Sample/MyContract] to [Bobby]
Grant references on message type::[//MyTest/Sample/ReplyMsg] to [Bobby]
Deny view definition on Route::ExpenseRoute to [Bobby]
Grant alter on route::ExpenseRoute to [Bobby]
Grant View Definition on Service::[//MyTest/Sample/InitSvc] to [Bobby]
Deny alter on Service::[//MyTest/Sample/InitSvc] to [Bobby]
create fulltext catalog ftCat as default;
create fulltext stoplist mystopList;
grant alter on fulltext catalog::ftcat to [Bobby]
Deny view definition on fulltext Stoplist::myStopList to [Bobby]
grant alter on fulltext Stoplist::myStopList to [Bobby]
go
USE master
GRANT VIEW SERVER STATE TO [bobby];