Skip to content

Commit fc4a74b

Browse files
committed
Add Examples, better build Outputs/Inputs swagger handling, checkin current Swagger
1 parent 3b5ec18 commit fc4a74b

File tree

7 files changed

+395
-16
lines changed

7 files changed

+395
-16
lines changed

Examples/Sync-UiPathADUsers.ps1

Lines changed: 355 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,355 @@
1+
<#
2+
.SYNOPSIS
3+
Synchronises Orchestrator users with Windows Active Directory, based on AD group membership mapped to Orchestrator Roles.
4+
.DESCRIPTION
5+
You provide the AD domain name and a mapping from relevand AD groups to Orchestrator Roles.
6+
New users in AD are added to Orchestrator and existing users added moved to the correct Role.
7+
The script also handles removing Orchestrator users from roles when they were removed from the corresponding AD group.
8+
AD users that were removed from all relevant AD groups (eg. an employee that changed role) or were removed from AD (eg. a former employee that left the company) become 'orphaned users'. They are still defined in Orchestrator but do not have any Role. The script supports the -OrphanedUsersAction parameter allowing to optionally List or Remove these users.
9+
The script is idempotent, repeated invocations should not modify the Orchestrator users unless something changed in AD.
10+
You should first import the UiPath.PowerShell module and authenticate yourself with your Orchestrator using Get-UiPathAuthToken before running this script.
11+
.PARAMETER DomainName
12+
The domain to sync users with. It does not necessarily has to be your current user or machine domain, but there must be some trust relationship so your Windows session can discover and interogate this domain AD.
13+
.PARAMETER RolesMapping
14+
A Hashtable mapping AD groups to Orchestrator roles. Make sure you type the names correctly.
15+
.PARAMETER OrphanedUsersAction
16+
Optional action to handle orphaned users. You can List or Remove these users.
17+
.EXAMPLE
18+
Sync-UiPathADUsers MyDomain @{'RPA Admins' = 'Administrator'; 'RPA Users' = 'User'}
19+
Import AD users from MyDomain and maps the members of the 'RPA Admins' AD group to the 'Administrator' Orchestrator role and members of the 'RPA Users' AD group to the 'User' Orchestrator role.
20+
.EXAMPLE
21+
Sync-UiPathADUsers MyDomain @{} -OrphanedUsersAction Remove
22+
Import AD users from MyDomain but since there is no mapping, the effect is to orphan all exiting Orchestrator MyDomain users and then remove them because of the -OrphanedUsersAction Remove parameter. In effect this invocation removes all MyDomain users from Orchestrator.
23+
#>
24+
param(
25+
[Parameter(Mandatory=$true, Position=0)]
26+
[string] $DomainName,
27+
[Parameter(Mandatory=$true, Position=1)]
28+
[HashTable] $RolesMapping,
29+
[Parameter(Mandatory=$false)]
30+
[ValidateSet('Remove', 'List', 'Ignore')]
31+
[string] $OrphanedUsersAction = 'Ignore'
32+
)
33+
34+
$ErrorActionPreference = "Stop"
35+
36+
function Get-ADGroupUser {
37+
param(
38+
[Parameter(Mandatory=$true, Position=0)] $dc,
39+
[Parameter(Mandatory=$true, Position=1)] $adGroup
40+
)
41+
42+
Write-Verbose "Get-ADGroupUser $adGroup"
43+
44+
$users = @()
45+
$members = Get-ADGroupMember -Server $dc.PDCEmulator -Identity $adGroup
46+
47+
foreach($member in $members)
48+
{
49+
if ($member.objectClass -eq 'user')
50+
{
51+
$users += @($member.SamAccountName)
52+
}
53+
elseif ($member.objectClass -eq 'group')
54+
{
55+
$childUsers = Get-ADGroupUser $dc $member.SamAccountName
56+
$users += $childUsers
57+
}
58+
}
59+
$users
60+
}
61+
62+
try
63+
{
64+
$operationSteps = @(
65+
"Validate Orchestrator role names", `
66+
"Extracting AD group members", `
67+
"Extracting Orchestrator users", `
68+
"Preparing sync operations", `
69+
"Importing New AD Users", `
70+
"Modifying user role membership", `
71+
"Process orphaned users"
72+
)
73+
74+
$idxOperationStep = 0
75+
Write-Progress -Activity "Sync Orchestrator AD Users" `
76+
-CurrentOperation $operationSteps[$idxOperationStep] `
77+
-PercentComplete ($idxOperationStep/$operationSteps.Count*100)
78+
$i = 1
79+
foreach($roleName in $RolesMapping.Values)
80+
{
81+
Write-Progress -Id 1 `
82+
-Activity $operationSteps[$idxOperationStep] `
83+
-CurrentOperation $roleName `
84+
-PercentComplete ($i/$RolesMapping.Values.Count*100)
85+
$i += 1
86+
$role = Get-UiPathRole -Name $roleName
87+
if ($role -eq $null)
88+
{
89+
throw "Could not find the Orchestrator role name: $roleName"
90+
}
91+
Write-Verbose "Role ok: $roleName $($role.Name)"
92+
}
93+
94+
Write-Verbose "Get-ADDomain $DomainName"
95+
$dc = Get-ADDomain -Identity $DomainName
96+
97+
$idxOperationStep += 1
98+
Write-Progress -Activity "Sync Orchestrator AD Users" `
99+
-CurrentOperation $operationSteps[$idxOperationStep] `
100+
-PercentComplete ($idxOperationStep/$operationSteps.Count*100)
101+
102+
[HashTable] $allADUsers = @{}
103+
104+
$i = 1
105+
foreach($adGoupName in $RolesMapping.Keys)
106+
{
107+
Write-Progress -Id 1 `
108+
-Activity $operationSteps[$idxOperationStep] `
109+
-PercentComplete ($i/$RolesMapping.Keys.Count *100) `
110+
-CurrentOperation $roleMap
111+
$i += 1
112+
113+
$mappedRole = $RolesMapping[$adGoupName]
114+
115+
$adGroupMembers = Get-ADGroupUser $dc $adGoupName | sort -Unique
116+
117+
foreach($adGroupMember in $adGroupMembers)
118+
{
119+
$userName = $DomainName + '\' + $adGroupMember
120+
$adUser = $allADUsers[$userName]
121+
if ($adUser -eq $null)
122+
{
123+
$adUser = @{ roles = @(); name = $adGroupMember.Name }
124+
$null = $allADUsers.Add($userName, $adUser)
125+
}
126+
Write-Verbose "Discovered AD user $userName with role $mappedRole"
127+
$adUser.roles += @($mappedRole)
128+
}
129+
}
130+
131+
$idxOperationStep += 1
132+
Write-Progress -Activity "Sync Orchestrator AD Users" `
133+
-CurrentOperation $operationSteps[$idxOperationStep] `
134+
-PercentComplete ($idxOperationStep/$operationSteps.Count*100)
135+
$orchestratorUsers = Get-UiPathUser -Type User | Select UserName, Id, RolesList | where {$_.UserName.StartsWith($DomainName + '\', [System.StringComparison]::OrdinalIgnoreCase)}
136+
137+
$idxOperationStep += 1
138+
Write-Progress -Activity "Sync Orchestrator AD Users" `
139+
-CurrentOperation $operationSteps[$idxOperationStep] `
140+
-PercentComplete ($idxOperationStep/$operationSteps.Count*100)
141+
142+
[HashTable] $operations = @{}
143+
144+
# Copy all Orchestrator users
145+
foreach($orchestratorUser in $orchestratorUsers)
146+
{
147+
$op = @{id = $orchestratorUser.Id; isNew = $false; existingRoles = $orchestratorUser.RolesList; newRoles = @()}
148+
$null = $operations.Add($orchestratorUser.UserName, $op)
149+
}
150+
151+
# Apply all AD users
152+
foreach($adUserName in $allADUsers.Keys)
153+
{
154+
$op = $operations[$adUserName]
155+
$adUser = $allADUsers[$adUserName]
156+
if ($op -eq $null)
157+
{
158+
$op = @{isNew = $true; adUser = $adUser}
159+
$operations.Add($adUserName, $op)
160+
}
161+
else
162+
{
163+
$op.newRoles += $adUser.roles
164+
}
165+
}
166+
167+
168+
# Figure add/remove list for each group and the new users that need to be added
169+
170+
$newUsers = @()
171+
$orphanedUsers = @()
172+
$changedRoles = @{}
173+
foreach($adUserName in $operations.Keys)
174+
{
175+
$op = $operations[$adUserName]
176+
if ($op.isNew -eq $true)
177+
{
178+
$newUsers += @{userName = $adUserName; name = $op.adUser.name; roles = $op.adUser.roles}
179+
}
180+
else
181+
{
182+
$idxExisting = 0
183+
$idxNew = 0
184+
185+
$existingRoles = $op.existingRoles | sort -Unique
186+
$newRoles = $op.newRoles | sort -Unique
187+
188+
# Oh, Powershell....
189+
if ($existingRoles -isnot [array])
190+
{
191+
$existingRoles = @($existingRoles)
192+
}
193+
194+
if ($newRoles -isnot [array])
195+
{
196+
$newRoles = @($newRoles)
197+
}
198+
199+
# because we sorted the two arrays we can use a merge algorithm
200+
201+
while($idxExisting -lt $existingRoles.Count -or $idxNew -lt $newRoles.Count)
202+
{
203+
$existingRole = $null
204+
$newRole = $null
205+
$changedRole = $null
206+
$addOrRemove = $null
207+
$roleName = $null
208+
209+
if ($idxExisting -lt $existingRoles.Count)
210+
{
211+
$existingRole = $existingRoles[$idxExisting]
212+
}
213+
214+
if ($idxNew -lt $newRoles.Count)
215+
{
216+
$newRole = $newRoles[$idxNew]
217+
}
218+
219+
if ($existingRole -eq $newRole)
220+
{
221+
# unchanged role, nothing to see here, move along
222+
$idxExisting += 1
223+
$idxNew += 1
224+
continue
225+
}
226+
elseif ($newRole -eq $null -or (($existingRole -ne $null) -and ($existingRole -lt $newRole)))
227+
{
228+
# user must be removed from this existing role
229+
$roleName = $existingRole
230+
$idxExisting += 1
231+
$addOrRemove = 'remove'
232+
}
233+
else
234+
{
235+
# user must be added to this new role
236+
$roleName = $newRole
237+
$idxNew += 1
238+
$addOrRemove = 'add'
239+
}
240+
$changedRole = $changedRoles[$roleName]
241+
if ($changedRole -eq $null)
242+
{
243+
$changedRole = @{addedUsers=@();removedUsers=@()}
244+
$changedRoles.Add($roleName, $changedRole)
245+
}
246+
if ($addOrRemove -eq 'add')
247+
{
248+
$changedRole.addedUsers += @($op.Id)
249+
}
250+
else
251+
{
252+
$changedRole.removedUsers += @($op.Id)
253+
}
254+
}
255+
256+
if ($newRoles.Count -eq 0)
257+
{
258+
Write-Verbose "Is orphaned: $adUserName"
259+
$orphanedUsers += @{userName = $adUserName; id = $op.Id}
260+
}
261+
}
262+
}
263+
264+
$idxOperationStep += 1
265+
Write-Progress -Activity "Sync Orchestrator AD Users" `
266+
-CurrentOperation $operationSteps[$idxOperationStep] `
267+
-PercentComplete ($idxOperationStep/$operationSteps.Count*100)
268+
269+
$i = 0
270+
foreach($newUser in $newUsers)
271+
{
272+
$i += 1
273+
274+
Write-Progress -Id 1 `
275+
-Activity $operationSteps[$idxOperationStep] `
276+
-CurrentOperation $newUser.userName `
277+
-PercentComplete ($i/$newUsers.Count * 100)
278+
279+
Write-Verbose "Add-UiPathUser -Username $newUser.userName -Name $($newUser.name) -RolesList $($newUser.roles)"
280+
$null = Add-UiPathUser -Username $newUser.userName -Name $newUser.name -RolesList $newUser.roles
281+
}
282+
283+
$idxOperationStep += 1
284+
Write-Progress -Activity "Sync Orchestrator AD Users" `
285+
-CurrentOperation $operationSteps[$idxOperationStep] `
286+
-PercentComplete ($idxOperationStep/$operationSteps.Count*100)
287+
288+
$i = 0
289+
foreach($changedRole in $changedRoles.Keys)
290+
{
291+
$i += 1
292+
$op = $changedRoles[$changedRole]
293+
294+
Write-Progress -Id 1 `
295+
-Activity $operationSteps[$idxOperationStep] `
296+
-CurrentOperation $changedRole `
297+
-PercentComplete ($i/$changedRoles.Keys.Count * 100)
298+
299+
Write-Verbose "Get-UiPathRole -Name $changedRole"
300+
$role = Get-UiPathRole -Name $changedRole
301+
302+
Write-Verbose "Edit-UiPathRoleUser $changedRole -Add $($op.addedUsers) -Remove $($op.removedUsers)"
303+
$null = Edit-UiPathRoleUser $role -Add $op.addedUsers -Remove $op.removedUsers
304+
}
305+
306+
$idxOperationStep += 1
307+
Write-Progress -Activity "Sync Orchestrator AD Users" `
308+
-CurrentOperation $operationSteps[$idxOperationStep] `
309+
-PercentComplete ($idxOperationStep/$operationSteps.Count*100)
310+
311+
switch($OrphanedUsersAction)
312+
{
313+
'Remove'
314+
{
315+
$i = 1
316+
foreach($orphanedUser in $orphanedUsers)
317+
{
318+
Write-Progress -Id 1 `
319+
-Activity "Remove orphaned users" `
320+
-CurrentOperation $orphanedUser.userName `
321+
-PercentComplete ($i/$orphanedUsers.Count * 100)
322+
$i += 1
323+
Write-Verbose "Remove-UiPathUser -Id $($orphanedUser.id)"
324+
Remove-UiPathUser -Id $orphanedUser.id
325+
}
326+
}
327+
'List'
328+
{
329+
foreach($orphanedUser in $orphanedUsers)
330+
{
331+
Write-Host $orphanedUser.userName
332+
}
333+
}
334+
'Ignore'
335+
{
336+
# No-op
337+
}
338+
}
339+
}
340+
catch
341+
{
342+
$e = $_.Exception
343+
$klass = $e.GetType().Name
344+
$line = $_.InvocationInfo.ScriptLineNumber
345+
$script = $_.InvocationInfo.ScriptName
346+
$msg = $e.Message
347+
348+
Write-Error "$klass $msg ($script $line)"
349+
}
350+
351+
352+
353+
354+
355+

Generate-CmdletDocs.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ $file = "docs\Home.md"
55
"" | Out-File $file -Encoding utf8
66
foreach($cmdlet in $cmdlets)
77
{
8-
"[$($cmdlet.Name)]($($cmdlet.Name).md)" | Out-File $file -Encoding utf8 -Append
8+
"- [$($cmdlet.Name)]($($cmdlet.Name).md)" | Out-File $file -Encoding utf8 -Append
99
}
1010

1111
foreach($cmdlet in $cmdlets)

Properties/GlobalAssemblyInfo.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,4 @@
1111

1212
// The version should be set to match the current released platform version
1313
//
14-
[assembly: AssemblyVersion("18.1.3.0")]
15-
[assembly: AssemblyFileVersion("18.1.3.0")]
14+
[assembly: AssemblyVersion("18.1.3.*")]

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ A PowerShell library for interacting with [UiPath Orchestrator](https://orchestr
44

55
# Getting Started
66

7-
Build solution to obtain the `UiPath.PowerShell.dll` module. Import the module in PowerShell:
7+
Download the desired version module from the [Releases](https://github.com/UiPath/orchestrator-powershell/releases) page, or build solution to obtain the `UiPath.PowerShell.dll` module. Import the module in PowerShell:
88

99
```PowerShell
1010
PS C:\>Import-Module UiPath.PowerShell.dll

0 commit comments

Comments
 (0)