Public/Import-Role.ps1
function Import-Role { <# .SYNOPSIS Imports Milestone user roles from a JSON file .DESCRIPTION Import a JSON file generated by Export-Role, or by hand or programatically for the purpose of bulk role creation or update. If the members of a role are determined by a system other than simple Active Directory security groups, you could for example use this function to quickly set the role members for one or more roles. If you do not care to update specific properties like Overall Security or Smart Client Profiles, you can set these properties to null and the import procedure will skip that property. This can greatly improve the import speed if you know you don't need to update certain properties. .EXAMPLE PS C:\> Import-Role -Path .\roles.json -DoNotRemoveMembers Import all roles from roles.json but do not remove members from any roles if they are not present in the Members property of the role in the JSON file. With the DoNotRemoveMembers switch, you will only add new users to the role if they are not already present - no users will be removed. #> [CmdletBinding(SupportsShouldProcess)] param ( # Specifies the path to a JSON file containing a list of objects with role information. Consider generating a template using Export-Role if you will be using this to bulk import role configuration [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'FromFile')] [string] $Path, # Specifies the pscustomobject array containing the a list of roles to be imported. [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'FromObject')] [pscustomobject] $InputObject, # Specifies that users should not be removed from roles if they are not present in the specified JSON file [Parameter()] [switch] $DoNotRemoveMembers, # Specifies that the Administrators role should be modified if the role is present in the specified JSON file and Viewgroups should be deleted if HasMatchingViewGroup is false. [Parameter()] [switch] $Force ) begin { $config = BuildConfigMemoryMap } process { $stopWatch = [Diagnostics.StopWatch]::new() <# Import JSON file#> $stopWatch.Restart() if ($PSCmdlet.ParameterSetName -eq 'FromFile') { Write-Verbose "Importing $Path" $rows = Get-Content -Path $Path | ConvertFrom-Json Write-Verbose "Completed JSON import in $($stopWatch.Elapsed.TotalSeconds) seconds" } else { $rows = $InputObject } $total = $rows.Count if ($total -le 0) { $total = 1 } $i = 0 $progressParams = @{ Activity = "Importing Roles" Status = "Working" CurrentOperation = "Waiting" PercentComplete = 0 } $rowStopWatch = [Diagnostics.StopWatch]::StartNew() foreach ($row in $rows) { $lastProcessingTime = $rowStopWatch.Elapsed $progressParams.PercentComplete = $i / $total * 100 $progressParams.Status = "Imported $i of $total roles" $progressParams.CurrentOperation = "Importing $($row.Name)" $progressParams.SecondsRemaining = [int]((($lastProcessingTime.TotalMilliseconds * $total) - ($lastProcessingTime.TotalMilliseconds * $i)) / 1000) Write-Progress @progressParams $i += 1 $rowStopWatch.Restart() Write-Verbose "Processing role '$($row.Name)'" <# Create the role or find it in the dictionary #> $stopWatch.Restart() Write-Verbose "Creating or retrieving role" if (-not $config.Roles.ContainsKey($row.Name)) { $roleParams = @{ Name = $row.Name } if (-not [string]::IsNullOrWhiteSpace($row.DualAuthorizationRequired)) { $roleParams.RequireDualAuth = $row.DualAuthorizationRequired } if (-not [string]::IsNullOrWhiteSpace($row.MakeUsersAnonymousDuringPTZSession)) { $roleParams.AnonymousPtz = $row.MakeUsersAnonymousDuringPTZSession } if (-not [string]::IsNullOrWhiteSpace($row.AllowMobileClientLogOn)) { $roleParams.AllowMobileClient = $row.AllowMobileClientLogOn } if (-not [string]::IsNullOrWhiteSpace($row.AllowSmartClientLogOn)) { $roleParams.AllowSmartClient = $row.AllowSmartClientLogOn } if (-not [string]::IsNullOrWhiteSpace($row.AllowWebClientLogOn)) { $roleParams.AllowWebClient = $row.AllowWebClientLogOn } if (-not [string]::IsNullOrWhiteSpace($row.Description)) { $roleParams.Description = $row.Description } if ($PSCmdlet.ShouldProcess($row.Name, "Create role")) { $role = Add-Role @roleParams if ($null -eq $role) { Write-Warning "Skipping $($row.Name) because the role does not exist and was unable to be created" continue } else { $config.Roles.$($row.Name) = $role } } else { continue } } else { $role = $config.Roles.$($row.Name) } Write-Verbose "Completed role creation/retrieval in $($stopWatch.Elapsed.TotalSeconds) seconds" <# Check that the properties all match and update them if they don't #> $stopWatch.Restart() Write-Verbose "Updating direct properties of role if necessary" $dirty = $false if ($null -ne $row.DualAuthorizationRequired -and $row.DualAuthorizationRequired -ne $role.DualAuthorizationRequired) { $role.DualAuthorizationRequired = $row.DualAuthorizationRequired $dirty = $true } if ($null -ne $row.MakeUsersAnonymousDuringPTZSession -and $role.MakeUsersAnonymousDuringPTZSession -ne $row.MakeUsersAnonymousDuringPTZSession) { $role.MakeUsersAnonymousDuringPTZSession = $row.MakeUsersAnonymousDuringPTZSession $dirty = $true } if ($null -ne $row.AllowMobileClientLogOn -and $role.AllowMobileClientLogOn -ne $row.AllowMobileClientLogOn) { $role.AllowMobileClientLogOn = $row.AllowMobileClientLogOn $dirty = $true } if ($null -ne $row.AllowSmartClientLogOn -and $role.AllowSmartClientLogOn -ne $row.AllowSmartClientLogOn) { $role.AllowSmartClientLogOn = $row.AllowSmartClientLogOn $dirty = $true } if ($null -ne $row.AllowWebClientLogOn -and $role.AllowWebClientLogOn -ne $row.AllowWebClientLogOn) { $role.AllowWebClientLogOn = $row.AllowWebClientLogOn $dirty = $true } if ($null -ne $row.Description -and $role.Description -ne $row.Description) { $role.Description = $row.Description $dirty = $true } if ($dirty) { if ($PSCmdlet.ShouldProcess($row.Name, "Save changes to role properties")) { $role.Save() } } Write-Verbose "Completed checking and updating properties in $($stopWatch.Elapsed.TotalSeconds) seconds" <# Update the ClientTimeProfile if necessary #> if ($null -ne $row.ClientTimeProfile) { $stopWatch.Restart() Write-Verbose "Updating ClientTimeProfile if necessary" $timeProfileInfo = $role.SetClientTimeProfile() if ($timeProfileInfo.ItemSelection -ne $row.ClientTimeProfile) { if (-not ($timeProfileInfo.ItemSelectionValues.ContainsKey($row.ClientTimeProfile))) { Write-Error "No Time Profile found matching '$($row.ClientTimeProfile)'. Valid options include $([string]::Join(', ', $timeProfileInfo.ItemSelectionValues.Keys))" } else { if ($PSCmdlet.ShouldProcess($row.Name, "Set ClientTimeProfile to $($row.ClientTimeProfile)")) { $timeProfileInfo.ItemSelection = $timeProfileInfo.ItemSelectionValues.$($row.ClientTimeProfile) $invokeResult = $timeProfileInfo.ExecuteDefault() if ($invokeResult.State -ne 'Success') { Write-Error "Failed to update ClientTimeProfile on $($role.Name): $($invokeResult.ErrorText)" } } } } Write-Verbose "Completed ClientTimeProfile update in $($stopWatch.Elapsed.TotalSeconds) seconds" } <# Update role members #> if ($null -ne $row.Members) { $stopWatch.Restart() Write-Verbose "Setting members for role" $role | Set-RoleMembership -Members $row.Members -DoNotRemoveMembers:$DoNotRemoveMembers -Force:$Force Write-Verbose "Completed Set-RoleMembers in $($stopWatch.Elapsed.TotalSeconds) seconds" } <# Update Overall Security #> if ($null -ne $row.OverallSecurity) { $overallSecurityKeys = $row.OverallSecurity | Get-Member -MemberType Properties | Select-Object -ExpandProperty Name $invokeInfo = $role.ChangeOverallSecurityPermissions() foreach ($key in $overallSecurityKeys) { if (-not $invokeInfo.SecurityNamespaceValues.ContainsValue($row.OverallSecurity.$key.SecurityNamespace)) { Write-Error "The Overall Security Namespace '$key' with NamespaceId '$($row.OverallSecurity.$key.SecurityNamespace)' does not exist." continue } $invokeInfo.SecurityNamespace = $row.OverallSecurity.$key.SecurityNamespace $namespaceInvokeInfo = $invokeInfo.ExecuteDefault() $securityAttributes = $row.OverallSecurity.$key | Get-Member -MemberType Properties | Select-Object -ExpandProperty Name $dirty = $false foreach ($attribute in $securityAttributes) { if ($namespaceInvokeInfo.GetProperty($attribute) -ne $row.OverallSecurity.$key.$attribute) { $namespaceInvokeInfo.SetProperty($attribute, $row.OverallSecurity.$key.$attribute) $dirty = $true } } if ($dirty) { if ($PSCmdlet.ShouldProcess($row.Name, "Update Overall Security / $($key)")) { $invokeResult = $namespaceInvokeInfo.ExecuteDefault() if ($invokeResult.State -ne 'Success') { Write-Error "Failed to change Overall Security for $($row.Name) in namespace '$($key)'" } } } } } <# Update Smart Client Profile #> if ($null -ne $row.SmartClientProfile) { $stopWatch.Restart() Write-Verbose "Updating Smart Client Profile if necessary" if ($config.RoleToSmartClientProfile.$($row.Name) -ne $row.SmartClientProfile) { if ($config.SmartClientProfiles.ContainsKey($row.SmartClientProfile)) { if ($PSCmdlet.ShouldProcess($row.Name, "Attach Smart Client Profile '$($row.SmartClientProfile)'")) { try { $config.SmartClientProfiles.$($row.SmartClientProfile).AttachToRole($role.Id) } catch { Write-Error $_ } } } else { Write-Error "Smart Client Profile '$($row.SmartClientProfile)' does not exist" } } Write-Verbose "Completed Smart Client Profile update in $($stopWatch.Elapsed.TotalSeconds) seconds" } <# Update Management Client Profile #> if ($null -ne $row.ManagementClientProfile) { $stopWatch.Restart() Write-Verbose "Updating Management Client Profile if necessary" if ($config.RoleToManagementClientProfile.$($row.Name) -ne $row.ManagementClientProfile) { if ($config.ManagementClientProfiles.ContainsKey($row.ManagementClientProfile)) { if ($PSCmdlet.ShouldProcess($row.Name, "Attach Management Client Profile '$($row.ManagementClientProfile)'")) { try { $config.ManagementClientProfiles.$($row.ManagementClientProfile).AttachToRole($role.Id) } catch { Write-Error $_ } } } else { Write-Error "Management Client Profile '$($row.ManagementClientProfile)' does not exist" } } Write-Verbose "Completed Management Client Profile update in $($stopWatch.Elapsed.TotalSeconds) seconds" } <# Add or remove the public viewgroup if necessary #> if ($null -ne $row.HasMatchingViewGroup) { $stopWatch.Restart() Write-Verbose "Updating Public View Group if necessary" if ($row.HasMatchingViewGroup -eq $true -and -not $config.ViewGroups.ContainsKey($row.Name)) { if ($PSCmdlet.ShouldProcess($row.Name, "Create View Group for role")) { Write-Verbose "Adding Public View Group to match role" $vg = New-PublicViewGroup -Name $row.Name if ($null -ne $vg) { $config.ViewGroups.Add($row.Name, $vg) } } } elseif ($row.HasMatchingViewGroup -eq $false -and $config.ViewGroups.ContainsKey($row.Name)) { if ($PSCmdlet.ShouldProcess($row.Name, "Delete View Group for role")) { $config.ViewGroups.$($row.Name).Delete() $config.ViewGroups.Remove($row.Name) } } if ($config.ViewGroups.ContainsKey($row.Name) -and $null -ne $row.ViewGroupPermissions) { $effectivePermissions = $config.ViewGroups.$($row.Name).EffectivePermissions("[VideoOS]\$($row.Name)") $permissionSet = [VideoOS.Management.VmoClient.PublicViewGroupPermissionSet]::new() foreach ($key in $row.ViewGroupPermissions | Get-Member -MemberType Properties | Select-Object -ExpandProperty Name) { if ($row.ViewGroupPermissions.$key -eq $true) { if ($key -eq 'Edit') { $key = "Write" } $permissionSet += [VideoOS.Management.VmoClient.PublicViewGroupPermission]::$key } } if ($effectivePermissions -ne $permissionSet) { if ($PSCmdlet.ShouldProcess($row.Name, "Update Public View Group permission set")) { Write-Verbose "Updating Public View Group Permissions" $config.ViewGroups.$($row.Name).Revoke($config.FullViewGroupPermissionSet, "[VideoOS]\$($row.Name)") if ($permissionSet -ne $config.EmptyViewGroupPermissionSet) { $config.ViewGroups.$($row.Name).Allow($permissionSet, "[VideoOS]\$($row.Name)") } } } } Write-Verbose "Completed Public View Group update in $($stopWatch.Elapsed.TotalSeconds) seconds" } Write-Verbose "Processed row in $($rowStopWatch.Elapsed.TotalSeconds) seconds" } } end { if ($null -ne $vmo) { $vmo.Dispose() } } } |