Blog Post

PowerShell : Scripting Logins, Role Assignments and Server Permissions Using PowerShell

,

This post is a continuation of Multiple DB refresh automation using PowerShell post . The OP requested me to automate the login transfer process as well. The script should generate an outfile and execute the file on the target server.

<#

.ProblemStatement

Copying SQL server logins to file is little bit tricky though we are able to generate the script the password need to handled in a proper way to make it work.

Usually we’ll make use of scripts like sp_help_revlogin to manage copying logins from one instance to another but the requirement won’t suffice our purpose it won’t generate the script for server permissions and role assignments.

When you are automating the entire refresh process,PowerShell provides a flexibility to run SQL and generate the scripts in the said path. The SQL file can be invoked using invoke-sqlcmd to to execute it across any target server

The below code loads the snapins

SqlServerProviderSnapin100

SqlServerCmdletSnapin100

.Example1

To generate the script

PS:\>Copy-Logins -SourceServer <SourceServer> -outpath E:\OutPut

.Example2

Generate and apply script on to the target server

PS P:\> Copy-Logins -SourceServer <SourceServer> -outpath E:\OutPut -TargetServer <ServerName>

.Reference Link

Scripting Out the Logins, Server Role Assignments, and Server Permissions

#>

 

function Copy-Logins{
    [cmdletbinding()]
    Param
    (
    [parameter(Mandatory=$true)][string] $Sourceserver,
    [String] $TargetServer,
    [string] $outpath)
##Create a new outfile at query function call
[string]$FileDS = Get-Date -Format "yyyyMMdd" 
[string]$outFile = $outpath +'\'+ $Sourceserver+'_'+$FileTS + "_login.sql" 
New-Item -ItemType file $outfile -Force
##Prepare the connection string 
$SqlConnection = New-Object System.Data.SQLClient.SQLConnection("Server=$Sourceserver;Integrated Security=sspi;");
$SqlCommand = New-Object System.Data.SQLClient.SqlCommand; 
$SqlCommand.Connection = $SqlConnection;   
Try
{
##SQL Account - Executing a SQL is better than working with Hashed value
$SQL=  "
-- Scripting Out the Logins To Be Created
SELECT 'IF (SUSER_ID('+QUOTENAME(SP.name,'''')+') IS NULL) BEGIN CREATE LOGIN ' +QUOTENAME(SP.name)+
   CASE 
WHEN SP.type_desc = 'SQL_LOGIN' THEN ' WITH PASSWORD = ' +CONVERT(NVARCHAR(MAX),SL.password_hash,1)+ ' HASHED, CHECK_EXPIRATION = ' 
+ CASE WHEN SL.is_expiration_checked = 1 THEN 'ON' ELSE 'OFF' END +', CHECK_POLICY = ' +CASE WHEN SL.is_policy_checked = 1 THEN 'ON,' ELSE 'OFF,' END
ELSE ' FROM WINDOWS WITH'
END 
   +' DEFAULT_DATABASE=[' +SP.default_database_name+ '], DEFAULT_LANGUAGE=[' +SP.default_language_name+ '] END;' COLLATE SQL_Latin1_General_CP1_CI_AS AS [-- Logins To Be Created --]
FROM sys.server_principals AS SP LEFT JOIN sys.sql_logins AS SL
ON SP.principal_id = SL.principal_id
WHERE SP.type IN ('S','G','U')
AND SP.name NOT LIKE '##%##'
AND SP.name NOT LIKE 'NT AUTHORITY%'
AND SP.name NOT LIKE 'NT SERVICE%'
AND SP.name <> ('sa')"
$SQL2="SELECT 
'EXEC master..sp_addsrvrolemember @loginame = N''' + SL.name + ''', @rolename = N''' + SR.name + '''
' AS [-- server Roles the Logins Need to be Added --]
FROM master.sys.server_role_members SRM
JOIN master.sys.server_principals SR ON SR.principal_id = SRM.role_principal_id
JOIN master.sys.server_principals SL ON SL.principal_id = SRM.member_principal_id
WHERE SL.type IN ('S','G','U')
AND SL.name NOT LIKE '##%##'
AND SL.name NOT LIKE 'NT AUTHORITY%'
AND SL.name NOT LIKE 'NT SERVICE%'
AND SL.name <> ('sa')"
$SQL3="
SELECT 
CASE WHEN SrvPerm.state_desc <> 'GRANT_WITH_GRANT_OPTION' 
THEN SrvPerm.state_desc 
ELSE 'GRANT' 
END
    + ' ' + SrvPerm.permission_name + ' TO [' + SP.name + ']' + 
CASE WHEN SrvPerm.state_desc <> 'GRANT_WITH_GRANT_OPTION' 
THEN '' 
ELSE ' WITH GRANT OPTION' 
END collate database_default AS [-- server Level Permissions to Be Granted --] 
FROM sys.server_permissions AS SrvPerm 
JOIN sys.server_principals AS SP ON SrvPerm.grantee_principal_id = SP.principal_id 
WHERE   SP.type IN ( 'S', 'U', 'G' ) 
AND SP.name NOT LIKE '##%##'
AND SP.name NOT LIKE 'NT AUTHORITY%'
AND SP.name NOT LIKE 'NT SERVICE%'
AND SP.name <> ('sa')"
 
        $SqlCommand.CommandText = $SQL;   
        $SqlConnection.Open(); 
        $table = $SqlCommand.ExecuteReader(); 
        While ($table.Read())
           {
               $table[0]+' '+"`r`n"+"GO"|Out-File -Append -FilePath $outfile
            } 
        $SqlConnection.Close();
        $SqlConnection.Open(); 
        $SqlCommand.CommandText = $SQL2;   
        $table = $SqlCommand.ExecuteReader(); 
        While ($table.Read())
           {
               $table[0]+' '+"`r`n"+"GO"|Out-File -Append -FilePath $outfile
            } 
        $SqlConnection.Close();
        $SqlConnection.Open(); 
        $SqlCommand.CommandText = $SQL3;   
        $table = $SqlCommand.ExecuteReader(); 
        While ($table.Read())
           {
               $table[0]+' '+"`r`n"+"GO"|Out-File -Append -FilePath $outfile
            } 
        $SqlConnection.Close();
}
catch
{
 $ErrorMessage = $_.Exception.Message
 Write-host "$Sourceserver does't exist or Invalid SQL instance Name $ErrorMessage"
}
if (!(Get-PSSnapin | ?{$_.name -eq 'SqlServerProviderSnapin100'})) 
{
   add-pssnapin SqlServerProviderSnapin100 
   write-host "Loading SqlServerProviderSnapin100 in session" 
} 
else 
{ 
  write-host "SqlServerProviderSnapin100 is already loaded" 
} 
if (!(Get-PSSnapin | ?{$_.name -eq 'SqlServerCmdletSnapin100'})) 
{   
    add-pssnapin SqlServerCmdletSnapin100 
   write-host "Loading SqlServerCmdletSnapin100 in session" 
} 
else 
{ 
  write-host "SqlServerCmdletSnapin100 is already loaded" 
} 
 If($TargetServer){
 try
    {
    Invoke-Sqlcmd -ServerInstance $TargetServer -InputFile $outFile -ErrorAction Stop
    }
catch
    {
     Write-host "$TargetServer not reachable "
     }
 }
}   
   

Please refer the below link which gives a full list of required details

SQL Server Instance Security: Scripting Permissions

 


Rate

You rated this post out of 5. Change rating

Share

Share

Rate

You rated this post out of 5. Change rating