Copying User Roles Between Environments in Service Manager 2012
If you’ve ever created user roles in a test or pre-production Service Manager environment and wanted to copy them to a production environment, you’ll have noticed there is no ability to export from one environment to another. Likewise, if you support multiple business units in your environment and therefore need multiple user roles that are very similar (for example, we have multiple user roles where the only differences are the views as well as the members), you’ll have noticed there is no easy way to make a copy of a user role, either. User roles are one of the few things in Service Manager that are not saved in management packs, and therefore can’t just be exported and imported at will.
Fortunately the Service Manager cmdlets offer a way to recreate user roles. With a little scripting, we can both export from one environment to another and create a duplicate within the same environment.
This script needs to be run on a computer that has the Service Manager console installed, as we rely on the built-in Service Manager PowerShell module.
You also need to be an admin in both the source and destination Service Manager environments.
If you have created custom user roles with the same names as the built-in ones, the script will not copy them over unless you explicitly call them out with the “role” switch.
The PowerShell script can be downloaded from https://gallery.technet.microsoft.com/Copying-User-Roles-Between-b5460847. Note that you may need to set your execution policy as unrestricted to run it since it wasn’t written on your local machine. To do this run the following in an elevated PowerShell window:
set-executionpolicy unrestricted
The PowerShell script is run as follows:
.\CopyRole.ps1 -from SourceServer -to DestinationServer -role NameOfRoleToExport -newrole NameOfNewRole
Where:
- From is the server you are copying the role(s) from
- To is the server you are copying the role(s) to (if different from the source server)
- Role is the name of the role you are copying (if not copying all roles)
- Newrole is the new name of the role you are copying (if you want to change the name)
The only required switch is the “From” switch.
If you aren’t interested in seeing how the script works, you can download the script and start running with it. Otherwise, the next section goes through how the script works. I break the script down in case it helps someone learn something new.
This script was a little more complicated to come up with simply because of the different components of a user role. Specifically we need to define all the classes, queues, groups, catalog groups, tasks, views, templates, and users when creating the new user role. Initially I saved each of these as variables and defined the respective switches in the new-scsmuserrole cmdlet, however if there were any null values in the variables the script would fail.
The solution to this was to create an empty user role, then for each of the variables that were not null, run the update-scsmuserrole cmdlet and add the various components to the role. This does add extra calls to the script, however they run quickly and should have a low impact.
Taking the script apart, we initially define our parameters:
param ($From, $To, $Role, $NewRole)
Adding some error handling to make sure we have the minimum information necessary to run, we ensure that “From” is defined and notify the user that if no “To” is defined we assume the source and destination servers are the same:
If (! $From) {Write-host "No source server specified. Please specify source server and try again" -fore red -back black; exit}
If (! $to) {$to = $from; write-host No `"to`" server specified`; Assuming copying to source server $From.toupper() -fore yellow}
We next import the Service Manager PowerShell module if not already imported:
#Load SM PS module if not already loaded
If ( ! (Get-module System.Center.Service.Manager )) { Import-Module "$env:programfiles\Microsoft System Center 2012\Service Manager\Powershell\System.Center.Service.Manager.psd1" }
Since we will be handling some of the errors ourselves, I initially suppress any error notifications and clear the $error variable. Later we will allow errors to be displayed as I don’t know all the different errors that users may run into:
#Clear error variable for better error handling
$error.clear()
#Set error action preference to hidden to not confuse users and handle errors ourselves
$ErrorActionPreference = "SilentlyContinue"
If the “Role” switch was defined we next retrieve the user role specified. If no role was defined we retrieve all user roles:
#Get the specified user role or all if not specified
write-host Getting user role`(s`) from $From.toupper()
If ($Role)
{
$AllUserRoles = get-scsmuserrole -displayname $Role -computer $From
} else
{
$AllUserRoles = get-scsmuserrole -computer $From
}
Since we just connected to the SDK server for the first time, we will error out if no connectivity could be made. Since this is the error we wanted to handle ourselves, we also set the error action to the default “continue” afterwards so users will see errors that PowerShell throws since we aren’t handling any additional errors after this point:
#Error if invalid SDK server specified
If ($error[0] -like "The Data Access service is either not running or not yet initialized*")
{
write-host Invalid management server specified. Please verify the `"computer`" switch and try again. -fore red -back black; exit
}
#Set error action preference to continue in case we missed handling any errors
$ErrorActionPreference = "Continue"
Since any new environment will already have the built-in user roles, we don’t want to copy these user roles to the new environment. We build a list of the names of the built-in user roles so we can exclude them when we do our copy. We next set $Role to contain either all user roles excluding the built-in ones, or else set it to what was defined in the “Role” switch:
If(! $Role)
{
$list = "Activity Implementers","Administrators","Advanced Operators","Authors","Change Initiators","Change Managers","End Users","Incident Resolvers","Problem Analysts","Read-Only Operators","Release Managers","Service Request Analysts","Workflows"
$Role = $alluserroles | where displayname -notin $list
} Else {
$Role = $alluserroles | where displayname -eq $Role
}
For each user role in the $Role variable, we next get each individual component of that user role and set them to their own variables. This includes the type, class, queue, group, catalog group, task, view, template, and users:
Foreach ($UserRole in $Role)
{
#Filter to specific role
#$UserRoleA = $AllUserRoles | where {$_.displayname -eq $UserRole}
#Get user role type
$Type = $UserRole.userrole.profile.name
#Getting the class
$class = $userrole | foreach {$_.classes}
#Getting the queue
$queue = $userrole | foreach {$_.queue}
#Getting the group
$group = $userrole | foreach {$_.group}
#Getting the catalog group
$cgroup = $userrole | foreach {$_.cataloggroup}
#Getting the tasks
$task = $userrole | foreach {$_.task}
#Getting the views
$view = $userrole | foreach {$_.view}
#Getting the template
$template = $userrole | foreach {$_.formtemplate}
#Getting the users
$user = $userrole | foreach {$_.user}
Since we need to update the user roles with the above variables after we have created the “shell” for the new user roles, we will be using the “passthru” switch after creating the user role and storing the new user role to variable “UserRoleEnvB”. When doing this we need to have the variable created first, so if it’s not already created we will create it:
#Remove and create a new variable to store the newly created variable in
if ($UserRoleEnvB) {remove-variable UserRoleEnvB}
new-variable UserRoleEnvB
We will next create the “shell” for each user role. If a list wasn’t defined and the “NewRole” switch wasn’t used, we will set $NewRole to the display name of the user role we are copying from:
#Creating the shell user role
If (($List) -or (! $NewRole)) {$NewRole = $UserRole.DisplayName}
If there was no description on the user role we are copying from, we will create the new user role without a description. Otherwise we will create it with a description. For both scenarios we pass through the newly created user role and store it in $UserRoleEnvB. Also notice that we defined the “type” of role the new user role is based on and keep the user informed of the progress:
If (! $UserRole.Description)
{
write-host Creating user role $NewRole in $To.toupper() -fore green new-scsmuserrole -userroletype $Type -computer $To -displayname $NewRole -passthru | set-variable UserRoleEnvB
} Else {
write-host Creating user role $NewRole in $To.toupper() -fore green new-scsmuserrole -userroletype $Type -computer $To -displayname $NewRole -Description $UserRole.Description -passthru | set-variable UserRoleEnvB
}
Lastly we will update the newly created user role with the class, queue, group, catalog group, task, view, template, and users if not null:
#If not null, add each item to the user role
If ($class)
{$UserRoleEnvB | %{$_.classes = $class; $_} | update-scsmuserrole}
If ($queue)
{$UserRoleEnvB | %{$_.queue = $queue; $_} | update-scsmuserrole}
If ($group)
{$UserRoleEnvB | %{$_.group = $group; $_} | update-scsmuserrole}
If ($cgroup)
{$UserRoleEnvB | %{$_.cataloggroup = $cgroup; $_} | update-scsmuserrole}
If ($task)
{$UserRoleEnvB | %{$_.task = $task; $_} | update-scsmuserrole}
If ($view)
{$UserRoleEnvB | %{$_.view = $view; $_} | update-scsmuserrole}
If ($template)
{$UserRoleEnvB | %{$_.formtemplate = $template; $_} | update-scsmuserrole}
If ($user)
{$UserRoleEnvB | %{$_.user = $user; $_} | update-scsmuserrole}
}
My next revisions of this script will include the ability to save the user role to a share for easy importing into a new Service Environment during a disaster recovery situation. Stay tuned!
Anonymous
January 01, 2003
The better way to filter build-in roles is to check IsSystem property: $Role = $alluserroles | ? {!$_.IsSystem}Anonymous
January 01, 2003
Thanks, I'll get rid of the list and implement this instead. Much appreciated!Anonymous
May 21, 2013
Hi, I got some errors, could you please help on this? PS C:tempScripts> .copyrole.ps1 -from serverscsm01 -role solutions -newrole production No "to" server specified; Assuming copying to source server serverscsm01 Getting user role(s) from serverscsm01 Where-Object : Cannot bind parameter 'FilterScript'. Cannot convert the "displayname" value of type "System.String" to type "System.Management.Automation.ScriptBlock". At C:tempScriptsCopyRole.ps1:42 char:30
- $Role = $alluserroles | where <<<< displayname -eq $Role + CategoryInfo : InvalidArgument: (:) [Where-Object], ParameterBi ndingException + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerSh ell.Commands.WhereObjectCommand Creating user role produccion in serverscsm01 New-SCSMUserRole : Cannot validate argument on parameter 'UserRoleType'. The argument is null or empty. Supply an argument that is not null or empty and then try the command again. At C:tempScriptsCopyRole.ps1:87 char:31
- new-scsmuserrole -userroletype <<<< $Type -computer $To -displayname $NewRol e -passthru | set-variable UserRoleEnvB + CategoryInfo : InvalidData: (:) [New-SCSMUserRole], ParameterBi ndingValidationException + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.Enter priseManagement.ServiceManager.Cmdlets.NewSCSMUserRoleCommand