如何检查SQL Server登录名是否具有角色'SysAdmin'

时间:2019-05-23 20:26:12

标签: sql-server powershell

我正在研究一个PowerShell脚本,该脚本检查指定的SQL Server,以查看是否已成功为特定的登录名(称为“ ContractUser”)授予了SysAdmin的角色。我正在寻找一种编写简单的if / then脚本的方法,以查看该登录名是否具有SysAdmin角色。

我在网上找到了许多示例,这些示例显示了如何检索SysAdmin登录名的整个列表,但是还没有弄清楚如何更改这些脚本以仅检查服务器中的单个登录名。例如,以下脚本使用SysAdmin角色获取所有登录名,然后对其进行特殊处理。

$SQLSvr = "SQLServername\Instancename";
$MySQL = New-Object Microsoft.SqlServer.Management.Smo.Server $SQLSvr;
$SQLLogins = $MySQL.Logins;

$SysAdmins = $null;
$SysAdmins = foreach ($SQLUser in $SQLLogins) {
    foreach ($role in $SQLUser.ListMembers()) {
        if ($role -match 'sysadmin') {
            ...do stuff...
        };
    };
};

我尝试进行一些更改,并提出了以下代码,该代码未返回预期的结果(我知道我正在检查的服务器具有该登录名,并且该登录名是sysadmin,但脚本另有说明) :

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo") | Out-Null

$serverConnection = New-Object Microsoft.SqlServer.Management.Common.ServerConnection
$serverConnection.ServerInstance=$SQLServer
$server = New-Object Microsoft.SqlServer.Management.SMO.Server($serverConnection)
$SQLLogins = $server.Logins
$loginIsSysadmin = "No"
foreach ($SQLLogin in $SQLLogins) {
    $SQLRoles = $SQLLogin.ListMembers()
    if ($SQLRoles -eq "SysAdmin" -and $SQLLogin.name -eq "ContractUser") {
        $loginIsSysadmin = "Yes"
        break
    }
}

我希望我的脚本可以将变量$loginIsSysadmin更改为“是”,然后可以针对输出和进一步操作进行简单检查。但是,运行脚本后,该变量仍为“否”。

任何关于我做错事情的输入都会受到赞赏。

2 个答案:

答案 0 :(得分:1)

IS_SRVROLEMEMBER(Transact-SQL)可能提供比直接SQL查询登录更全面的方法。例如,它检查:

  1. 登录名是否存在(如果存在),是否是sysadmin的直接或间接成员。
  2. 如果不存在,则它是通过本身映射到登录名的Windows组(或组组)的间接成员身份而成为sysadmin的成员。

https://docs.microsoft.com/en-us/sql/t-sql/functions/is-srvrolemember-transact-sql?view=sql-server-ver15

请参见下面的示例用法:

function QueryDatabaseScript($databaseServer, $dbScript, $timeout)
{
    # Query and return recordset array for passed T-SQL string
    $SQLConnection = New-Object System.Data.SqlClient.SqlConnection
    $SQLConnection.ConnectionString = "server=$($databaseServer);Initial Catalog=master;Integrated Security=True;"

    try
    {        
        $SQLConnection.Open()
        $SQLCommand = New-Object System.Data.SqlClient.SqlCommand
        $SQLCommand.Connection = $SQLConnection 
        $SQLCommand.CommandTimeout = $timeout
        
        $SQLCommand.CommandText = $dbScript
        $reader = $SQLCommand.ExecuteReader()

        $recordsetArray = @()
        while ($reader.Read())
        {
            $recordsetArray += $reader[0]
        }

        $SQLConnection.Close()
        $SQLConnection.Dispose()
    }
    catch
    {
        write-host "QueryDatabaseScript failed.`nError: $($_.Exception.Message)"
        $SQLConnection.Dispose()
        throw $_
    }

    return $recordsetArray
}

$sqlSvr = 'SQLServername\Instancename';

$queryResults = QueryDatabaseScript $sqlSvr "select Is_SrvRoleMember('sysadmin')" 0
$isSysadmin = $queryResults[0]
write-host "Current user is a sysadmin: $isSysadmin"

$sqlLogin = 'ContractUser'
$queryResults = QueryDatabaseScript $sqlSvr "select Is_SrvRoleMember('sysadmin', '$sqlLogin')" 0
$isSysadmin = $queryResults[0]
write-host "$sqlLogin is a sysadmin: $isSysadmin"

答案 1 :(得分:0)

在这里,像往常一样,invoke-sqlcmd是您的朋友。 SMO不是。

例如

$login = 'sa'
$sql = @"
    select r.name role_name, m.name member_name
    from sys.server_principals r
    join sys.server_role_members rm
      on r.principal_id = rm.role_principal_id
    join sys.server_principals m
      on m.principal_id = rm.member_principal_id
    where m.name = '$login'
"@
$isSysadmin = ( @(invoke-sqlcmd $sql ).Count -eq 1 )
write-host "Is a sysadmin: $isSysadmin"