internal/Update-SqlPermissions.ps1
function Update-SqlPermissions { <# .SYNOPSIS Internal function. Updates permission sets, roles, database mappings on server and databases #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [object]$sourceserver, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [object]$sourcelogin, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [object]$destserver, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [object]$destlogin, [switch]$Silent ) $destination = $destserver.DomainInstanceName $source = $sourceserver.DomainInstanceName $username = $sourcelogin.name # Server Roles: sysadmin, bulklogin, etc foreach ($role in $sourceserver.roles) { $rolename = $role.name $destrole = $destserver.roles[$rolename] if ($destrole -ne $null) { try { $destrolemembers = $destrole.EnumMemberNames() } catch { $destrolemembers = $destrole.EnumServerRoleMembers() } } try { $rolemembers = $role.EnumMemberNames() } catch { $rolemembers = $role.EnumServerRoleMembers() } if ($rolemembers -contains $username) { if ($destrole -ne $null) { If ($Pscmdlet.ShouldProcess($destination, "Adding $username to $rolename server role")) { try { $destrole.AddMember($username) Write-Message -Level Verbose -Message "Added $username to $rolename server role." } catch { Stop-Function -Message "Failed to add $username to $rolename server role." -Target $role -ErrorRecord $_ } } } } # Remove for Syncs if ($rolemembers -notcontains $username -and $destrolemembers -contains $username -and $destrole -ne $null) { If ($Pscmdlet.ShouldProcess($destination, "Adding $username to $rolename server role")) { try { $destrole.DropMember($username) Write-Message -Level Verbose -Message "Removed $username from $destrolename server role on $($destserver.name)." } catch { Stop-Function -Message "Failed to remove $username from $destrolename server role on $($destserver.name)." -Target $role -ErrorRecord $_ } } } } $ownedjobs = $sourceserver.JobServer.Jobs | Where-Object { $_.OwnerLoginName -eq $username } foreach ($ownedjob in $ownedjobs) { if ($destserver.JobServer.Jobs[$ownedjob.name] -ne $null) { If ($Pscmdlet.ShouldProcess($destination, "Changing job owner to $username for $($ownedjob.name)")) { try { Write-Message -Level Verbose -Message "Changing job owner to $username for $($ownedjob.name)" $destownedjob = $destserver.JobServer.Jobs | Where-Object { $_.name -eq $ownedjobs.name } $destownedjob.set_OwnerLoginName($username) $destownedjob.Alter() } catch { Stop-Function -Message "Could not change job owner for $($ownedjob.name)" -Target $ownedJob -ErrorRecord $_ } } } } if ($sourceserver.versionMajor -ge 9 -and $destserver.versionMajor -ge 9) { # These operations are only supported by SQL Server 2005 and above. # Securables: Connect SQL, View any database, Administer Bulk Operations, etc. $perms = $sourceserver.EnumServerPermissions($username) foreach ($perm in $perms) { $permstate = $perm.permissionstate if ($permstate -eq "GrantWithGrant") { $grantwithgrant = $true; $permstate = "grant" } else { $grantwithgrant = $false } $permset = New-Object Microsoft.SqlServer.Management.Smo.ServerPermissionSet($perm.permissiontype) If ($Pscmdlet.ShouldProcess($destination, "Performing $permstate on $($perm.permissiontype) for $username")) { try { $destserver.PSObject.Methods[$permstate].Invoke($permset, $username, $grantwithgrant) Write-Message -Level Verbose -Message "Successfully performed $permstate $($perm.permissiontype) to $username" } catch { Stop-Function -Message "Failed to $permstate $($perm.permissiontype) to $username" -Target $perm -ErrorRecord $_ } } # for Syncs $destperms = $destserver.EnumServerPermissions($username) foreach ($perm in $destperms) { $permstate = $perm.permissionstate $sourceperm = $perms | Where-Object { $_.PermissionType -eq $perm.Permissiontype -and $_.PermissionState -eq $permstate } if ($sourceperm -eq $null) { If ($Pscmdlet.ShouldProcess($destination, "Performing Revoke on $($perm.permissiontype) for $username")) { try { $permset = New-Object Microsoft.SqlServer.Management.Smo.ServerPermissionSet($perm.permissiontype) if ($permstate -eq "GrantWithGrant") { $grantwithgrant = $true; $permstate = "grant" } else { $grantwithgrant = $false } $destserver.PSObject.Methods["Revoke"].Invoke($permset, $username, $false, $grantwithgrant) Write-Message -Level Verbose -Message "Successfully revoked $($perm.permissiontype) from $username" } catch { Stop-Function -Message "Failed to revoke $($perm.permissiontype) from $username" -Target $perm -ErrorRecord $_ } } } } } # Credential mapping. Credential removal not currently supported for Syncs. $logincredentials = $sourceserver.credentials | Where-Object { $_.Identity -eq $sourcelogin.name } foreach ($credential in $logincredentials) { if ($destserver.Credentials[$credential.name] -eq $null) { If ($Pscmdlet.ShouldProcess($destination, "Adding $($credential.name) to $username")) { try { $newcred = New-Object Microsoft.SqlServer.Management.Smo.Credential($destserver, $credential.name) $newcred.identity = $sourcelogin.name $newcred.Create() Write-Message -Level Verbose -Message "Successfully created credential for $username" } catch { Stop-Function -Message "Failed to create credential for $username" -Target $credential -ErrorRecord $_ } } } } } if ($destserver.versionMajor -lt 9) { Write-Message -Level Warning -Message "Database mappings skipped when destination is SQL Server 2000"; continue } # For Sync, if info doesn't exist in EnumDatabaseMappings, then no big deal. foreach ($db in $destlogin.EnumDatabaseMappings()) { $dbname = $db.dbname $destdb = $destserver.databases[$dbname] $sourcedb = $sourceserver.databases[$dbname] $dbusername = $db.username; $dblogin = $db.loginName if ($sourcedb -ne $null -and $sourcedb.IsAccessible) { if ($sourcedb.users[$dbusername] -eq $null -and $destdb.users[$dbusername] -ne $null) { If ($Pscmdlet.ShouldProcess($destination, "Dropping $dbusername from $dbname on destination.")) { try { $destdb.users[$dbusername].Drop() Write-Message -Level Verbose -Message "Dropped user $dbusername (login: $dblogin) from $dbname on destination. User may own a schema." } catch { Stop-Function -Message "Failed to drop $dbusername ($dblogin) from $dbname on destination." -Target $db -ErrorRecord $_ } } } # Remove user from role. Role removal not currently supported for Syncs. # TODO: reassign if dbo, application roles foreach ($destrole in $destdb.roles) { $destrolename = $destrole.name $sourcerole = $sourcedb.roles[$destrolename] if ($sourcerole -ne $null) { if ($sourcerole.EnumMembers() -notcontains $dbusername -and $destrole.EnumMembers() -contains $dbusername) { if ($dbusername -ne "dbo") { If ($Pscmdlet.ShouldProcess($destination, "Dropping $username from $destrolename database role on $dbname")) { try { $destrole.DropMember($dbusername) $destdb.Alter() Write-Message -Level Verbose -Message "Dropped username $dbusername (login: $dblogin) from $destrolename on $destination" } catch { Stop-Function -Message "Failed to remove $dbusername from $destrolename database role on $dbname." -Target $destrole -ErrorRecord $_ } } } } } } # Remove Connect, Alter Any Assembly, etc $destperms = $destdb.EnumDatabasePermissions($username) $perms = $sourcedb.EnumDatabasePermissions($username) # for Syncs foreach ($perm in $destperms) { $permstate = $perm.permissionstate $sourceperm = $perms | Where-Object { $_.PermissionType -eq $perm.Permissiontype -and $_.PermissionState -eq $permstate } if ($sourceperm -eq $null) { If ($Pscmdlet.ShouldProcess($destination, "Performing Revoke on $($perm.permissiontype) for $username on $dbname on $destination")) { try { $permset = New-Object Microsoft.SqlServer.Management.Smo.DatabasePermissionSet($perm.permissiontype) if ($permstate -eq "GrantWithGrant") { $grantwithgrant = $true; $permstate = "grant" } else { $grantwithgrant = $false } $destdb.PSObject.Methods["Revoke"].Invoke($permset, $username, $false, $grantwithgrant) Write-Message -Level Verbose -Message "Successfully revoked $($perm.permissiontype) from $username on $dbname on $destination" } catch { Stop-Function -Message "Failed to revoke $($perm.permissiontype) from $username on $dbname on $destination" -Target $perm -ErrorRecord $_ } } } } } } # Adding database mappings and securables foreach ($db in $sourcelogin.EnumDatabaseMappings()) { $dbname = $db.dbname $destdb = $destserver.databases[$dbname] $sourcedb = $sourceserver.databases[$dbname] $dbusername = $db.username; $dblogin = $db.loginName if ($destdb -ne $null) { if (!$destdb.IsAccessible) { Write-Message -Level Verbose -Message "Database [$($destdb.Name)] is not accessible. Skipping" Continue } if ($destdb.users[$dbusername] -eq $null) { If ($Pscmdlet.ShouldProcess($destination, "Adding $dbusername to $dbname")) { $sql = $sourceserver.databases[$dbname].users[$dbusername].script() | Out-String $sql = $sql -replace [Regex]::Escape("'$source'"), "'$destination'" try { $destdb.ExecuteNonQuery($sql) Write-Message -Level Verbose -Message "Added user $dbusername (login: $dblogin) to $dbname" } catch { Stop-Function -Message "Failed to add $dbusername ($dblogin) to $dbname on $destination." -Target $db -ErrorRecord $_ } } } # Db owner If ($sourcedb.owner -eq $username) { If ($Pscmdlet.ShouldProcess($destination, "Changing $dbname dbowner to $username")) { try { $result = Update-SqlDbOwner $sourceserver $destserver -dbname $dbname if ($result -eq $true) { Write-Message -Level Verbose -Message "Changed $($destdb.name) owner to $($sourcedb.owner)." } else { Write-Message -Level Warning -Message "Failed to update $($destdb.name) owner to $($sourcedb.owner)." } } catch { Write-Message -Level Warning -Message "Failed to update $($destdb.name) owner to $($sourcedb.owner)." } } } # Database Roles: db_owner, db_datareader, etc foreach ($role in $sourcedb.roles) { if ($role.EnumMembers() -contains $username) { $rolename = $role.name $destdbrole = $destdb.roles[$rolename] if ($destdbrole -ne $null -and $dbusername -ne "dbo" -and $destdbrole.EnumMembers() -notcontains $username) { If ($Pscmdlet.ShouldProcess($destination, "Adding $username to $rolename database role on $dbname")) { try { $destdbrole.AddMember($username) $destdb.Alter() Write-Message -Level Verbose -Message "Added $username to $rolename database role on $dbname." } catch { Stop-Function -Message "Failed to add $username to $rolename database role on $dbname." -Target $role -InnerErroRecord $_ } } } } } # Connect, Alter Any Assembly, etc $perms = $sourcedb.EnumDatabasePermissions($username) foreach ($perm in $perms) { $permstate = $perm.permissionstate if ($permstate -eq "GrantWithGrant") { $grantwithgrant = $true; $permstate = "grant" } else { $grantwithgrant = $false } $permset = New-Object Microsoft.SqlServer.Management.Smo.DatabasePermissionSet($perm.permissiontype) If ($Pscmdlet.ShouldProcess($destination, "Performing $permstate on $($perm.permissiontype) for $username on $dbname")) { try { $destdb.PSObject.Methods[$permstate].Invoke($permset, $username, $grantwithgrant) Write-Message -Level Verbose -Message "Successfully performed $permstate $($perm.permissiontype) to $username on $dbname" } catch { Stop-Function -Message "Failed to perform $permstate on $($perm.permissiontype) for $username on $dbname." -Target $perm -ErrorRecord $_ } } } } } } |