问题

  对于DBA或者其他运维人员来说授权一个账户的相同权限给另一个账户是一个很普通的任务。但是随着服务器、数据库、应用、使用人员地增加就变得很枯燥乏味又耗时费力的工作。那么有什么容易的办法来实现这个任务吗?

当然,作为非DBA在测试甚至开发环境也会遇到这种问题,要求授予所有服务器数据库的某个权限给一个人的时候。我们是不是有什么其他办法提高效率?

解决方案

  如果这个时候我们网上去搜索解决方案,大多数时候搜到的都是使用T-SQL解决方案,但是这又会产生下面几个小问题:

  1. 我们需要到目标服务器上执行这些脚本,有的甚至还需要部署后执行一遍。
  2. 不能生成这些T-SQL脚本到一个文件中。
  3. 重度使用的动态脚本代码冗长不方便阅读和维护。

本篇技巧的主要目的就是提供一个更好的基于PowerShell和SMO的解决方案来解决上述问题。

新的PS方法

  1. 在cmdlet函数中,可以接收一个SQLServer实例名称的列表以及登陆名($OldLogin),这些登陆名的权限是准备复制的。
  2. 对于每个实例,使用SMO Server.EnumObjectPermissions(loginName) 来获取服务对象(如登陆账号)权限并且使用Server.EnumServerPermissions(loginName) 来获取服务器级别的权限。
  3. 使用Login.EnumDatabaseMappings()来查找每个存在数据库登陆账户映射$OldLogin账户关系的数据库
  4. 在每个映射用户的数据库中,我们可以通过Database.EnumDatabasePermissions , Database.EnumObjectPermissions, User.EnumRoles, 和 EnumObjectPermissions 来获得用户的证书、对称以及非对称秘钥、ServiceBrokers等等来检索用户的所有权限。
  5. 所有检索到的权限信息将被添加到一个哈希表的数组汇总,然后通过循环数组导出权限脚本到一个文件中或者运行这个脚本用来复制一个新的账户权限。

测试环境

  现在我把从网上找到的脚本进行修改完善,然后如下的脚本列出来如下:

-- setup.sql to set up test environment
-- 1st: Set up login account and assign a few permissions plus role memberships
--setup.sql to set up test environment
-- 1st: Set up login account and assign a few permissions plus role memberships
USE master;
GO if exists (select * from sys.server_principals where name = 'Bobby')
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>
</xsd:schema>' ;
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];
 

在这个环境中,把所有不同的grant/deny 权限,来自用户[Bobby]的权限,不论是服务器登陆账户还是数据库账户的权限都获取了。总之,这就是一个权限 的grant/deny 脚本。

-- summary script
-- as server Login account
use Master;
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]; GRANT VIEW SERVER STATE TO [bobby];
GO -- as db account in [TestA] db
Use TestA
EXEC sp_addrolemember @rolename = 'db_securityadmin', @membername = 'Bobby';
EXEC sp_addrolemember @rolename = 'TestRoleInTestA', @membername = 'Bobby'; 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; 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]
GO -- as db account in [TestB] db
use TestB
EXEC sp_addsrvrolemember @loginame = 'Bobby', @rolename = 'securityadmin';
EXEC sp_addsrvrolemember @loginame = 'Bobby', @rolename = 'dbcreator'; 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]; GRANT ALTER ON XML SCHEMA COLLECTION::dbo.XSC TO [BOBBY];
DENY TAKE OWNERSHIP ON XML SCHEMA COLLECTION::dbo.XSC TO [BOBBY];
GO

  在我本地的电脑上,我有两个数据库实例,一个叫做[TP_W520](默认),另一个叫做[TP_W520\SQL2014]。分别在两个实例上运行。ok,接下来就是PowerShell 脚本了。

#requires -version 3.0
add-type -assembly "Microsoft.SqlServer.Smo, Version=11.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91"; #if Version-11.xx means sql server 2012 function Clone-SQLLogin
{
[CmdletBinding(SupportsShouldProcess=$true)] Param
(
# Param1 help description
[Parameter(Mandatory=$true,
ValueFromPipeline=$true,
Position=0)]
[string[]] $ServerInstance, [Parameter(Mandatory=$true)]
[string] $OldLogin, [Parameter(Mandatory=$true)]
[string] $NewLogin, [string] $NewPassword="", [string] $FilePath="",
[switch] $Execute
) Begin
{
[string]$newUser=$newLogin.Substring($newLogin.IndexOf('\')+1); # if $newLogin is a Windows account, such as domain\username, since "\" is invalid in db user name, we need to remove it [hashtable[]] $hta = @(); # a hashtable array
[hashtable] $h = @{}; if ( ($FilePath -ne "") -and (test-path -Path $FilePath))
{ del -Path $filepath; }
}
Process
{ foreach ($sqlinstance in $ServerInstance)
{ $svr = new-object "Microsoft.SqlServer.Management.Smo.Server" $sqlinstance;
if ($svr.Edition -eq $null)
{
Write-warning "$sqlinstance cannot be connected";
continue;
} [string]$str = ""; if (-not $WindowsLogin)
{
$str += "create login $($newLogin) with password='$($newPassword)'; `r`n"
}
else
{
$str += "create login $($newLogin) from windows;`r`n "
} #find role membership for $login
if ($svr.logins[$OldLogin] -ne $null)
{ $svr.logins[$oldLogin].ListMembers() | % {$str += "exec sp_addsrvrolemember @loginame = '$($newLogin)', @rolename = '$($_)'; `r`n"};}
else
{ Write-warning "$oldLogin does not exist on server [$($svr.name)] so this sql instance is skipped"; continue; } # find permission granted to $login $svr.EnumObjectPermissions($oldLogin) | % { if ($_.PermissionState -eq 'GrantWithGrant')
{$str += "GRANT $($_.PermissionType) on $($_.ObjectClass)::[$($_.ObjectName)] to [$newLogin] WITH GRANT OPTION; `r`n"}
else
{ $str += "$($_.PermissionState) $($_.PermissionType) on $($_.ObjectClass)::[$($_.ObjectName)] to [$newLogin]; `r`n"} } $svr.EnumServerPermissions($oldLogin) | % { if ($_.PermissionState -eq 'GrantWithGrant')
{ $str += "GRANT $($_.PermissionType) to [$newLogin] WITH GRANT OPTION; `r`n"}
else
{ $str += "$($_.PermissionState) $($_.PermissionType) to [$newLogin]; `r`n" } } $h = @{Server=$sqlinstance; DBName = 'master'; sqlcmd = $str};
$hta += $h;
#$str; $ObjPerms = @(); # store login mapped users in each db on $svr
$Roles = @();
$DBPerms = @();
foreach ($itm in $svr.logins[$oldLogin].EnumDatabaseMappings())
{
if ($svr.Databases[$itm.DBName].Status -ne 'Normal')
{ continue;} if ($svr.Databases[$itm.DBName].Users[$newUser] -eq $null)
{ $hta += @{Server=$sqlinstance; DBName = $itm.DBName; sqlcmd = "create user [$newUser] for login [$newLogin];`r`n" }; } $r = $svr.Databases[$itm.DBName].Users[$itm.UserName].EnumRoles();
if ($r -ne $null)
{
$r | % { $hta += @{Server=$sqlinstance; DBName = $itm.DBName; sqlcmd = "exec sp_addrolemember @rolename='$_', @memberName='$($newUser)';`r`n" } }
} $p = $svr.Databases[$itm.DBName].EnumDatabasePermissions($itm.UserName);
if ($p -ne $null)
{ $ObjPerms += @{DBName=$itm.DBName; Permission=$p};} $p = $svr.Databases[$itm.DBName].EnumObjectPermissions($itm.UserName)
if ($p -ne $null)
{ $ObjPerms += @{DBName=$itm.DBName; Permission=$p}; } $p = $svr.Databases[$itm.DBName].Certificates | % {$_.EnumObjectPermissions($itm.UserName)}
if ($p -ne $null)
{ $ObjPerms += @{DBName=$itm.DBName; Permission=$p};} #AsymmetricKeys
$p = $svr.Databases[$itm.DBName].AsymmetricKeys | % {$_.EnumObjectPermissions($itm.UserName)}
if ($p -ne $null)
{ $ObjPerms += @{DBName=$itm.DBName; Permission=$p}; } #SymmetricKeys
$p = $svr.Databases[$itm.DBName].SymmetricKeys | % {$_.EnumObjectPermissions($itm.UserName)}
if ($p -ne $null)
{ $ObjPerms += @{DBName=$itm.DBName; Permission=$p};} #XMLSchemaCollections
$p = $svr.Databases[$itm.DBName].XMLSchemaCollections | % {$_.EnumObjectPermissions($itm.UserName)}
if ($p -ne $null)
{ $ObjPerms += @{DBName=$itm.DBName; Permission=$p};} #service broker components
$p = $svr.Databases[$itm.DBName].ServiceBroker.MessageTypes | % {$_.EnumObjectPermissions($itm.UserName)}
if ($p -ne $null)
{ $ObjPerms += @{DBName=$itm.DBName; Permission=$p};} $p = $svr.Databases[$itm.DBName].ServiceBroker.Routes | % {$_.EnumObjectPermissions($itm.UserName)}
if ($p -ne $null)
{ $ObjPerms += @{DBName=$itm.DBName; Permission=$p};} $p = $svr.Databases[$itm.DBName].ServiceBroker.ServiceContracts | % {$_.EnumObjectPermissions($itm.UserName)}
if ($p -ne $null)
{ $ObjPerms += @{DBName=$itm.DBName; Permission=$p};} $p = $svr.Databases[$itm.DBName].ServiceBroker.Services | % {$_.EnumObjectPermissions($itm.UserName)}
if ($p -ne $null)
{ $ObjPerms += @{DBName=$itm.DBName; Permission=$p};} #Full text
$p = $svr.Databases[$itm.DBName].FullTextCatalogs | % {$_.EnumObjectPermissions($itm.UserName)}
if ($p -ne $null)
{ $ObjPerms += @{DBName=$itm.DBName; Permission=$p};} $p = $svr.Databases[$itm.DBName].FullTextStopLists | % {$_.EnumObjectPermissions($itm.UserName)}
if ($p -ne $null)
{ $ObjPerms += @{DBName=$itm.DBName; Permission=$p};}
} #generate t-sql to apply permission using SMO only
#[string]$str = ([System.String]::Empty)
foreach ($pr in $ObjPerms)
{ $h = @{Server=$sqlinstance; DBName=$($pr.DBName); sqlcmd=""};
$str = "" #"use $($pr.DBName) `r`n"
foreach ($p in $pr.Permission)
{
[string]$op_state = $p.PermissionState; if ($p.ObjectClass -ne "ObjectOrColumn")
{
[string] $schema = ""; if ($p.ObjectSchema -ne $null)
{ $schema = "$($p.ObjectSchema)."} [string]$option = ""; if ($op_state -eq "GRANTwithGrant")
{
$op_state = 'GRANT';
$option = ' WITH GRANT OPTION';
} Switch ($p.ObjectClass)
{
'Database' { $str += "$op_state $($p.PermissionType) to [$newUser]$option;`r`n";}
'SqlAssembly' { $str += "$op_state $($p.PermissionType) ON Assembly::$($schema)$($p.ObjectName) to [$newUser]$option;`r`n";}
'Schema' { $str += "$op_state $($p.PermissionType) ON SCHEMA::$($schema)$($p.ObjectName) to [$newUser]$option;`r`n";}
'UserDefinedType' { $str += "$op_state $($p.PermissionType) ON TYPE::$($schema)$($p.ObjectName) to [$newUser]$option;`r`n";}
'AsymmetricKey' { $str += "$op_state $($p.PermissionType) ON ASYMMETRIC KEY::$($schema)$($p.ObjectName) to [$newUser]$option;`r`n";}
'SymmetricKey' { $str += "$op_state $($p.PermissionType) ON SYMMETRIC KEY::$($schema)$($p.ObjectName) to [$newUser]$option;`r`n";}
'Certificate' { $str += "$op_state $($p.PermissionType) ON Certificate::$($schema)$($p.ObjectName) to [$newUser]$option`r`n";}
'XmlNamespace' { $str += "$op_state $($p.PermissionType) ON XML SCHEMA COLLECTION::$($schema)$($p.ObjectName) to [$newUser]$option`r`n";}
'FullTextCatalog' { $str += "$op_state $($p.PermissionType) ON FullText Catalog::$($schema)[$($p.ObjectName)] to [$newUser]$option`r`n";}
'FullTextStopList' { $str += "$op_state $($p.PermissionType) ON FullText Stoplist::$($schema)[$($p.ObjectName)] to [$newUser]$option`r`n";}
'MessageType' { $str += "$op_state $($p.PermissionType) ON Message Type::$($schema)[$($p.ObjectName)] to [$newUser]$option`r`n";}
'ServiceContract' { $str += "$op_state $($p.PermissionType) ON Contract::$($schema)[$($p.ObjectName)] to [$newUser]$option`r`n";}
'ServiceRoute' { $str += "$op_state $($p.PermissionType) ON Route::$($schema)[$($p.ObjectName)] to [$newUser]$option`r`n";}
'Service' { $str += "$op_state $($p.PermissionType) ON Service::$($schema)[$($p.ObjectName)] to [$newUser]$option`r`n";}
#you can add other stuff like Available Group etc in this switch block as well
}#switch }
else
{
[string]$col = "" #if grant is on column level, we need to capture it
if ($p.ColumnName -ne $null)
{ $col = "($($p.ColumnName))"}; $str += "$op_state $($p.PermissionType) ON Object::$($p.ObjectSchema).$($p.ObjectName) $col to [$newUser];`r`n";
}#else }
#$str += "go`r`n";
$h.sqlcmd = $str;
$hta += $h;
} }#loop $ServerInstance
} #process block
End
{
[string] $sqlcmd = ""; if ($FilePath.Length -gt 3) # $FilePath is provided
{
[string]$servername=""; foreach ($h in $hta)
{
if ($h.Server -ne $Servername)
{
$ServerName=$h.Server;
$sqlcmd += ":connect $servername `r`n"
} $sqlcmd += "use $($h.DBName);`r`n" + $h.sqlcmd +"`r`ngo`r`n"; }
$sqlcmd | out-file -FilePath $FilePath -Append ;
} if ($Execute)
{
foreach ($h in $hta)
{
$server = new-object "Microsoft.sqlserver.management.smo.server" $h.Server;
$database = $server.databases[$h.DBName];
$database.ExecuteNonQuery($h.sqlcmd)
}
} #$Execute }#end block
} #clone-sqllogin # test, change parameters to your own. The following creates a script about all permissions assigned to [Bobby]
# Clone-SQLLogin -Server "$env:ComputerName", "$env:ComputerName\sql2014" -OldLogin Bobby -NewLogin Bobby -FilePath "c:\temp\Bobby_perm.sql";

开始测试

  打开一个PowerShell ISE的窗口,复制、黏贴这个PS脚本到一个新的窗口,然后还需要取消最后一行的注释(还有修改服务器参数的名称:-Server parameter),接着运行脚本。

你将会看到一个新生成位于c:\temp\Bobby_perm.sql 的脚本。然后在NotePad 中打开这个脚本,如下:


:connect TP_W520
use master;
create login Bobby with password='';
exec sp_addsrvrolemember @loginame = 'Bobby', @rolename = 'securityadmin';
exec sp_addsrvrolemember @loginame = 'Bobby', @rolename = 'dbcreator';
Grant IMPERSONATE on Login::[sa] to [Bobby];
Grant VIEW DEFINITION on Login::[sa] to [Bobby];
Grant ALTER on Endpoint::[TSQL Default TCP] to [Bobby];
GRANT ALTER ANY LOGIN to [Bobby] WITH GRANT OPTION;
Grant ALTER ANY SERVER ROLE to [Bobby];
Grant CONTROL SERVER to [Bobby];
Grant CONNECT SQL to [Bobby];
Grant VIEW SERVER STATE to [Bobby]; go
use TestA;
exec sp_addrolemember @rolename='TestRoleInTestA', @memberName='Bobby'; go
use TestA;
exec sp_addrolemember @rolename='db_securityadmin', @memberName='Bobby'; go
use TestA;
Grant CONNECT to [Bobby];
GRANT CREATE PROCEDURE to [Bobby] WITH GRANT OPTION;
Grant CREATE TABLE to [Bobby]; go
use TestA;
Deny UPDATE ON Object::dbo.t to [Bobby];
Grant SELECT ON Object::dbo.t (a) to [Bobby];
Grant SELECT ON Object::dbo.t (d) to [Bobby];
Grant SELECT ON SCHEMA::dbo to [Bobby];
Grant ALTER ON FullText Catalog::[ftCat] to [Bobby] go
use TestA;
Grant REFERENCES ON Message Type::[//MyTest/Sample/ReplyMsg] to [Bobby] go
use TestA;
Grant ALTER ON Route::[ExpenseRoute] to [Bobby]
Deny VIEW DEFINITION ON Route::[ExpenseRoute] to [Bobby] go
use TestA;
Grant ALTER ON Contract::[//Mytest/Sample/MyContract] to [Bobby] go
use TestA;
Deny ALTER ON Service::[//MyTest/Sample/InitSvc] to [Bobby]
Grant VIEW DEFINITION ON Service::[//MyTest/Sample/InitSvc] to [Bobby] go
use TestA;
Grant ALTER ON FullText Catalog::[ftCat] to [Bobby] go
use TestA;
Grant ALTER ON FullText Stoplist::[mystopList] to [Bobby]
Deny VIEW DEFINITION ON FullText Stoplist::[mystopList] to [Bobby] go
use TestB;
Grant CONNECT to [Bobby]; go
use TestB;
Deny VIEW DEFINITION ON Object::dbo.SimpleProc to [Bobby];
Grant EXECUTE ON Object::dbo.SimpleProc to [Bobby]; go
use TestB;
Grant VIEW DEFINITION ON Certificate::TestCert to [Bobby] go
use TestB;
Grant CONTROL ON ASYMMETRIC KEY::ASymKey to [Bobby]; go
use TestB;
Grant CONTROL ON SYMMETRIC KEY::SymKey1 to [Bobby];
Grant CONTROL ON SYMMETRIC KEY::SymKey2 to [Bobby]; go
use TestB;
Grant ALTER ON XML SCHEMA COLLECTION::dbo.XSC to [Bobby]
Deny TAKE OWNERSHIP ON XML SCHEMA COLLECTION::dbo.XSC to [Bobby] go
:connect TP_W520\sql2014
use master;
create login Bobby with password='';
exec sp_addsrvrolemember @loginame = 'Bobby', @rolename = 'securityadmin';
exec sp_addsrvrolemember @loginame = 'Bobby', @rolename = 'dbcreator';
Grant IMPERSONATE on Login::[sa] to [Bobby];
Grant VIEW DEFINITION on Login::[sa] to [Bobby];
Grant ALTER on Endpoint::[TSQL Default TCP] to [Bobby];
GRANT ALTER ANY LOGIN to [Bobby] WITH GRANT OPTION;
Grant ALTER ANY SERVER ROLE to [Bobby];
Grant CONTROL SERVER to [Bobby];
Grant CONNECT SQL to [Bobby];
Grant VIEW SERVER STATE to [Bobby]; go
use TestA;
exec sp_addrolemember @rolename='TestRoleInTestA', @memberName='Bobby'; go
use TestA;
exec sp_addrolemember @rolename='db_securityadmin', @memberName='Bobby'; go
use TestA;
Grant CONNECT to [Bobby];
GRANT CREATE PROCEDURE to [Bobby] WITH GRANT OPTION;
Grant CREATE TABLE to [Bobby]; go
use TestA;
Deny UPDATE ON Object::dbo.t to [Bobby];
Grant SELECT ON Object::dbo.t (a) to [Bobby];
Grant SELECT ON Object::dbo.t (d) to [Bobby];
Grant SELECT ON SCHEMA::dbo to [Bobby];
Grant ALTER ON FullText Catalog::[ftCat] to [Bobby] go
use TestA;
Grant REFERENCES ON Message Type::[//MyTest/Sample/ReplyMsg] to [Bobby] go
use TestA;
Grant ALTER ON Route::[ExpenseRoute] to [Bobby]
Deny VIEW DEFINITION ON Route::[ExpenseRoute] to [Bobby] go
use TestA;
Grant ALTER ON Contract::[//Mytest/Sample/MyContract] to [Bobby] go
use TestA;
Deny ALTER ON Service::[//MyTest/Sample/InitSvc] to [Bobby]
Grant VIEW DEFINITION ON Service::[//MyTest/Sample/InitSvc] to [Bobby] go
use TestA;
Grant ALTER ON FullText Catalog::[ftCat] to [Bobby] go
use TestA;
Grant ALTER ON FullText Stoplist::[mystopList] to [Bobby]
Deny VIEW DEFINITION ON FullText Stoplist::[mystopList] to [Bobby] go
use TestB;
Grant CONNECT to [Bobby]; go
use TestB;
Deny VIEW DEFINITION ON Object::dbo.SimpleProc to [Bobby];
Grant EXECUTE ON Object::dbo.SimpleProc to [Bobby]; go
use TestB;
Grant VIEW DEFINITION ON Certificate::TestCert to [Bobby] go
use TestB;
Grant CONTROL ON ASYMMETRIC KEY::ASymKey to [Bobby]; go
use TestB;
Grant CONTROL ON SYMMETRIC KEY::SymKey1 to [Bobby];
Grant CONTROL ON SYMMETRIC KEY::SymKey2 to [Bobby]; go
use TestB;
Grant ALTER ON XML SCHEMA COLLECTION::dbo.XSC to [Bobby]
Deny TAKE OWNERSHIP ON XML SCHEMA COLLECTION::dbo.XSC to [Bobby] go


 注意: 看到生成的脚本与我们之前总结的有一点不同,因为授权的同时默认授权的了连接权限。否则,如果连接不被许可那么第一步创建账户都不能实现。

现在我们看一下复制[Bobby]权限到新账户[Johnny]。其中为[Johnny]生成权限审计脚本。使用如下两行:

# clone [Bobby] to [Johnny]
Clone-SQLLogin -Server $Env:ComputerName, "$ENV:COMPUTERNAME\sql2014" -OldLogin Bobby -NewLogin Johnny -NewPassword "P@s$w0Rd" -Execute; # generate a permission auditing script, change parameter valeus to your needs, make sure [OldLogin] and [NewLogin] are same.
Clone-SQLLogin -Server $Env:ComputerName, "$ENV:COMPUTERNAME\sql2014" -OldLogin Johnny -NewLogin Johnny -FilePath "c:\temp\Johnny_perm.sql";

我们可以比较之前的c:\temp\Bobby_perm.sql与新的c:\temp\Johnny_perm.sql  然后发现他们是完全一样的除了账户名称。

总结

  查找并复制用户的权限在SQLServer内是一个普遍的任务。利用这个技巧我们可以创建一个高级的PowerShell 函数来做这个工作来处理多服务器的情况,没必要去分别到目标服务器去执行代码。同时建议将这个PS脚本放到一个module中来正常使用,因此当你需要的时候只需要加在PS文件就可以自动加载该功能了。

  这个脚本适合我当前的工作,但是如果想进一步升级这个功能比如属性列表和可利用群组等权限则还需要进一步完善,同时要求数据库是2012及其以后版本才能支持。由于目前我的服务器还存在大量2008r2 所有我只能暂时忽略这些了。不过目前看也是够用了。

利用PowerShell复制SQLServer账户的所有权限的更多相关文章

  1. 利用PowerShell+Jenkins,实现项目的自动化部署

    当项目越来越庞大,部署环境越来越多以后,就会越来越依赖于自动化.比如本人公司的项目,目前有6个web和4个windows service,同时本地有两套环境:开发自测试环境和QA测试环境.每次版本发布 ...

  2. SharePoint自动化部署,利用PowerShell 导出/导入AD中的用户

    这几个月一直在帮客户改需求,部署.我已经心力憔悴,经过一段时间的摸索,我对用PowerShell实现自动化部署也有了一些心得,比如说利用PowerShell导出导入AD中的User.在基于ShareP ...

  3. 开发环境入门 linux基础 (部分) 复制 用户和组操作 权限更改

    复制 用户和组操作 权限更改 CP 复制命令 cp 源文件 目标文件 a) –r(recursive,递归的):递归地复制目录.当复制一个目录时,复制该目录中所有的内容,其中包括子目录的全部内容. b ...

  4. 利用Powershell和ceye.io实现Windows账户密码回传

    利用Powershell和ceye.io实现Windows账户密码回传 转自:http://www.freebuf.com/articles/system/129068.html 最近在研究Power ...

  5. 为运行Microsoft Dynamics CRM 异步处理服务指定账户没有性能计数器权限

    CRM 2016 安装 为运行Microsoft Dynamics CRM 应用程序指定账户没有性能计数器权限 为运行Microsoft Dynamics CRM 异步处理服务指定账户没有性能计数器权 ...

  6. 如何给EOS账户设置自定义权限

    https://bihu.com/article/1508858 EOS从上线以后,不断有传出token被盗的消息,安全无小事,我们一定要重视,今天从EOS帐户自己定义权限的角度来谈谈如何做好账户的安 ...

  7. SharePoint自动化部署,利用PowerShell 导入用户至AD——PART II

    这是对上一篇文章<SharePoint自动化部署,利用PowerShell 导出/导入AD中的用户>进行补充.开发时,为了测试和演示,我们往往需要经常性的把用户添加到AD中.数据量小的时候 ...

  8. 利用powershell进行windows日志分析

    0x00 前言 Windows 中提供了 2 个分析事件日志的 PowerShell cmdlet:一个是Get-WinEvent,超级强大,但使用起来比较麻烦:另一个是Get-EventLog,使得 ...

  9. 利用Powershell查询AD中账号属性

    标签:AD账号信息 最后登录时间 最后修改密码.SID 账号SID 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://hubuxcg ...

随机推荐

  1. 基于spring注解AOP的异常处理

    一.前言 项目刚刚开发的时候,并没有做好充足的准备.开发到一定程度的时候才会想到还有一些问题没有解决.就比如今天我要说的一个问题:异常的处理.写程序的时候一般都会通过try...catch...fin ...

  2. Android 判断一个 View 是否可见 getLocalVisibleRect(rect) 与 getGlobalVisibleRect(rect)

    Android 判断一个 View 是否可见 getLocalVisibleRect(rect) 与 getGlobalVisibleRect(rect) [TOC] 这两个方法的区别 View.ge ...

  3. Linux scp 设置nohup后台运行

    Linux scp 设置nohup后台运行 1.正常执行scp命令 2.输入ctrl + z 暂停任务 3.bg将其放入后台 4.disown -h 将这个作业忽略HUP信号 5.测试会话中断,任务继 ...

  4. 如何在ASP.Net创建各种3D图表

    我们都知道,图表在ASP.NET技术中是一种特别受欢迎而又很重要的工具.图表是表示数据的图形,一般含有X和Y两个坐标轴.我们可以用折线,柱状,块状来表示数据.通过图表控件,我们即能表示数据又能比较各种 ...

  5. System.Guid ToString五中格式

    参考:https://msdn.microsoft.com/en-us/library/97af8hh4.aspx 测试代码: using System; using System.Collectio ...

  6. fir.im Weekly - 关于 iOS10 适配、开发、推送的一切

    "小程序"来了,微信变成名副其实的 Web OS,新一轮的Web App 与Native App争论四起.程序员对新技术永远保持灵敏的嗅觉和旺盛的好奇心,@李锦发整理了微信小程序资 ...

  7. 游戏AI系列内容 咋样才能做个有意思的AI呢

    游戏AI系列内容 咋样才能做个有意思的AI呢 写在前面的话 怪物AI怎么才能做的比较有意思.其实这个命题有点大,我作为一个仅仅进入游戏行业两年接触怪物AI还不到一年的程序员来说,来谈这个话题,我想我是 ...

  8. Configure a bridged network interface for KVM using RHEL 5.4 or later?

    environment Red Hat Enterprise Linux 5.4 or later Red Hat Enterprise Linux 6.0 or later KVM virtual ...

  9. win10系统下连接无线网络掉线问题解决办法

    打开驱动精灵----系统诊断 找一个可修复的驱动点击 选择连不上网中的查看更多 有连不上网络,网络连接受限,解决无线间歇性掉网问题 进入计算机管理----设备管理 修改无线网络属性(名称含有wirel ...

  10. Windows cmd 长时间不输出新内容 直到按下ctrl + c 取消或者回车的解决办法

    换了一台新电脑, 在使用 ant 拷贝大量文件的时候 cmd 窗口过了很久没有继续输出新的内容,远远超过平时的耗时, 以为已经卡死 按下 ctrl + c 取消, 这时并没有取消, 而是输出了新内容, ...