Public/Push-AzureADUsersToBB.ps1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 |
Function Push-AzureADUsersToBB { <# .SYNOPSIS Takes users via the pipeline from Get-MgUser or from the deprecated Get-AzureADUser, converts the information needed and process it directly in GoBright .DESCRIPTION Takes users via the pipeline from Get-MgUser or from the deprecated Get-AzureADUser, converts the information needed and process it directly in GoBright .PARAMETER ADUserNamePropertyName Optional AzureAd User Property which contains the name of the user, in case you do not want to use the default property .PARAMETER ADUserPincodePropertyName Optional AzureAd User Property which contains the pincode .PARAMETER ADUserMobilePropertyName Optional AzureAd User Property which contains the mobile phone number .PARAMETER ADUserNFCIdPropertyName Optional AzureAd User Property which contains the NFC Identifier, note that this must be in hex format, example: XX:XX:XX .PARAMETER ADUserDefaultCostCenterIdOrNamePropertyName Optional AzureAd User Property which contains the Default Cost Center for the user, which can be the Name or the Id, both the name or id can be found in the GoBright portal .PARAMETER BrightBookingApiUrl Address of the GoBright API, e.g.: https://t1b.gobright.cloud/ .PARAMETER BrightBookingApiKey API key of the user to use to process the import .PARAMETER BrightBookingIntegrationName Name of the GoBright integration to link the users to .PARAMETER UserRoleNameForNewUsers Name of the GoBright userrole to link new users to .PARAMETER UserDefaultRoleName Optional default name of role the role the user should get (will be assigned to every user, except for the matches found in 'GroupUserRoleMapping') .PARAMETER GroupUserRoleMapping Optional map of AzureADRoleName and the corresponding role name that should be assigned. First match will be taken, and will override a potential given 'UserDefaultRoleName' Examplestructure to supply in this parameter: $groupToRoleMapping = @() $groupToRoleMapping += @{AzureADRoleName = "Group name A"; RoleName = "Bookingmanagers"} $groupToRoleMapping += @{AzureADRoleName = ""; RoleName = "Standard user role"; MatchType = "AddForEveryUser"} # NOTE: Here a special case, by setting MatchType = "AddForEveryUser", every user will be assigned to this "Standard user role" .PARAMETER DeactivateExistingUsersInSameIntegrationThatAreNotLoaded Deactivate users that exist in the platform in the same integration but are not loaded anymore from AD (e.g. because they are not anymore in the group you filter on) .PARAMETER IncludeUsersWithoutAzureADAssignedLicensesOrAssignedPlans Include users that do not have AzureAD licenses assigned (would otherwise be included as inactive) or AzureAD licenses assigned (would otherwise be fully excluded). Note that including these users might result in having unintended 'users' like serviceacounts, roommailbox users, etc. That can be mitigated by filtering the users before feeding them into this command. .PARAMETER WhatIf Use the WhatIf switch to print out the retreived users, without processing them to the API. This is usefull for testing purposes .EXAMPLE Get-MgUser -All -Select Id,DisplayName,Mail,UserPrincipalName,AccountEnabled,MobilePhone,AssignedLicenses | Push-AzureADUsersToBB -BrightBookingApiUrl "https://xyz.gobright.cloud/" -BrightBookingApiKey "[your api key]" -BrightBookingIntegrationName "Office 365" # Get all users in the AzureAD and let GoBright process it directly .LINK Get-MgUser #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low')] Param( [Parameter(Mandatory = $True, ValueFromPipeline = $True)] [System.Object[]]$pipelineInput, [Parameter(Mandatory = $False)] [string]$ADUserEmailAddressPropertyName = "Mail", [Parameter(Mandatory = $False)] [ValidateSet("None", "UserPrincipalName")] [string]$ADUserSpecificUsername = "None", [Parameter(Mandatory = $False)] [string]$ADUserNamePropertyName = "DisplayName", [Parameter(Mandatory = $False)] [string]$ADUserPincodePropertyName, [Parameter(Mandatory = $False)] [string]$ADUserMobilePropertyName = "MobilePhone", [Parameter(Mandatory = $False)] [string]$ADUserNFCIdPropertyName, [Parameter(Mandatory = $False)] [string]$ADUserDefaultCostCenterIdOrNamePropertyName, [Parameter(Mandatory = $True)] [string]$BrightBookingApiUrl, [Parameter(Mandatory = $True)] [string]$BrightBookingApiKey, [Parameter(Mandatory = $True)] [string]$BrightBookingIntegrationName, [Parameter(Mandatory = $False)] [string]$UserRoleNameForNewUsers, [Parameter(Mandatory = $False)] [string]$UserDefaultRoleName, [Parameter(Mandatory = $False)] [System.Object[]]$GroupUserRoleMapping, [switch]$DeactivateExistingUsersInSameIntegrationThatAreNotLoaded, [switch]$IncludeUsersWithoutAzureADAssignedLicensesOrAssignedPlans ) Begin { If (-not $PSBoundParameters.ContainsKey('Confirm')) { $ConfirmPreference = $PSCmdlet.SessionState.PSVariable.GetValue('ConfirmPreference') } If (-not $PSBoundParameters.ContainsKey('WhatIf')) { $WhatIfPreference = $PSCmdlet.SessionState.PSVariable.GetValue('WhatIfPreference') } $convertedUsers = @() $pipelineAzureADUsers = [System.Collections.Generic.List[Object]]::new() } Process { # collect all input users $pipelineAzureADUsers.Add($_) } End { # make the list unique, so we don't have duplicates $pipelineAzureADUsers = $pipelineAzureADUsers | Sort-Object -Property * -Unique # auto detect if the new Microsoft.Graph.Users module is used, or the old AzureAD module $UseDeprecatedAzureADModule = $False Foreach ($ADUser in $pipelineAzureADUsers) { If ($ADUser.GetType().FullName.StartsWith("Microsoft.Open.AzureAD","CurrentCultureIgnoreCase")) { $UseDeprecatedAzureADModule = $True Write-Warning "Detected user data that is loaded from the AzureAD module, please note that the AzureAD module is deprecated from 1st July 2023, visit https://support.gobright.com to migrate to the new Microsoft.Graph.Users module" } Else { If ($ADUser.GetType().FullName.StartsWith("Microsoft.Graph.PowerShell","CurrentCultureIgnoreCase")) { # user is loaded with Microsoft.Graph module } } break } # if using deprecated AzureAD module, then set the ADUserMobilePropertyName back to the default of the deprecated AzureAD module If ($UseDeprecatedAzureADModule) { If ($ADUserMobilePropertyName -eq "MobilePhone") { $ADUserMobilePropertyName = "Mobile" } } # prepare the user-role mapping If ($GroupUserRoleMapping) { Write-Output "Loading AzureAD groups for configured groups in the group to role mapping" # lookup a groupname, we do this in the order of the supplied key/values, and the first hit is taken. Foreach ($groupUserRoleMappingItem in $GroupUserRoleMapping) { If (-not ((-not $groupUserRoleMappingItem.RoleType) -or ($groupUserRoleMappingItem.RoleType -eq "MWV") -or ($groupUserRoleMappingItem.RoleType -eq "View"))) { Write-Warning "RoleType is not correct for role '$($groupUserRoleMappingItem.RoleName)', valid RoleType values are: MWV or View, but found: '$($groupUserRoleMappingItem.RoleType)', this rolemapping will be skipped" continue } If ($groupUserRoleMappingItem.MatchType -eq "AddForEveryUser") { # for this special match type we should not load the users of the group, because it is designed to matche always (and probably does not even have an AzureADRoleName set) Write-Output " - Special MatchType 'AddForEveryUser' found, every user will be added to the role '$($groupUserRoleMappingItem.RoleName)'" } Else { $foundGroup = $null # try to find the related group by name If ($UseDeprecatedAzureADModule) { $foundGroups = Get-AzureADGroup -Filter "DisplayName eq '$($groupUserRoleMappingItem.AzureADRoleName)'" } Else { [array]$foundGroups = Get-MgGroup -Filter "DisplayName eq '$($groupUserRoleMappingItem.AzureADRoleName)'" } If ($foundGroups.Count -ge 1) { # add the object id of the group to the mapping, so we can use it later on $foundGroup = $foundGroups[0] } $memberUserObjectIds = @() If ($foundGroup) { If ($UseDeprecatedAzureADModule) { $azureADGroupMembers = Get-AzureADGroupMember -All $true -ObjectId $foundGroup.ObjectId } Else { $azureADGroupMembers = Get-MgGroupMember -All -GroupId $foundGroup.Id } Foreach ($azureADGroupMember in $azureADGroupMembers) { If ($UseDeprecatedAzureADModule) { $memberUserObjectIds += $azureADGroupMember.ObjectId } Else { $memberUserObjectIds += $azureADGroupMember.Id } } Write-Output " - Group '$($foundGroup.DisplayName)' found, contains $($memberUserObjectIds.Count) users" } Else { Write-Warning " - Group '$($groupUserRoleMappingItem.AzureADRoleName)' not found in AzureAD, so users cannot be mapped to this group" } $groupUserRoleMappingItem | Add-Member MemberUserObjectIds $memberUserObjectIds -Force } } Write-Output "Finished loading AzureAD group info" } # process the users given in the pipeline Foreach ($ADUser in $pipelineAzureADUsers) { # load the basic information fields from the user object $userEmailAddress = "" If ($ADUserEmailAddressPropertyName) { $userEmailAddress = $ADUser.$ADUserEmailAddressPropertyName } Else { $userEmailAddress = $ADUser.Mail } $userName = "" If ($ADUserNamePropertyName) { $userName = $ADUser.$ADUserNamePropertyName } Else { $userName = $ADUser.DisplayName } $userAuthenticationUsername = "" if ($ADUserSpecificUsername -like "UserPrincipalName") { $userAuthenticationUsername = $ADUser.UserPrincipalName } $userMobile = "" If ($ADUserMobilePropertyName) { $userMobile = $ADUser.$ADUserMobilePropertyName } $userNFCId = "" If ($ADUserNFCIdPropertyName) { $userNFCId = $ADUser.$ADUserNFCIdPropertyName } $userDefaultCostCenterIdOrName = "" If ($ADUserDefaultCostCenterIdOrNamePropertyName) { $userDefaultCostCenterIdOrName = $ADUser.$ADUserDefaultCostCenterIdOrNamePropertyName } $userEnabled = $false If ($ADUser.AccountEnabled -And ($ADUser.AssignedLicenses -Or $IncludeUsersWithoutAzureADAssignedLicensesOrAssignedPlans) -And $userEmailAddress) { $userEnabled = $true } $userPincode = "" If ($ADUserPincodePropertyName) { $userPincode = $ADUser.$ADUserPincodePropertyName } $userMappedRoles = @() If ($GroupUserRoleMapping) { # lookup which roles are valid for this user Foreach ($groupUserRoleMappingItem in $GroupUserRoleMapping) { $userMatches = $false # check if there is a 'special' matchtype, and otherwise match the default way If ($groupUserRoleMappingItem.MatchType -eq "AddForEveryUser") { $userMatches = $true } Else { If ($UseDeprecatedAzureADModule) { If ($groupUserRoleMappingItem.MemberUserObjectIds -contains $ADUser.ObjectId) { $userMatches = $true } } Else { If ($groupUserRoleMappingItem.MemberUserObjectIds -contains $ADUser.Id) { $userMatches = $true } } } If ($userMatches) { $propertiesHash = [ordered]@{ RoleName = $groupUserRoleMappingItem.RoleName RoleType = $groupUserRoleMappingItem.RoleType } $userMappedRoles += New-Object PSObject -Property $propertiesHash } } } # if nothing matched, then add the default rolename If ($UserDefaultRoleName) { If ($userMappedRoles.Count -eq 0) { $propertiesHash = [ordered]@{ RoleName = $UserDefaultRoleName } $userMappedRoles += New-Object PSObject -Property $propertiesHash } } If ($UseDeprecatedAzureADModule) { $uniqueImportID = $ADUser.ObjectId $hasAssignedLicenses = $ADUser.AssignedPlans } Else { $uniqueImportID = $ADUser.Id $hasAssignedLicenses = $ADUser.AssignedLicenses } $outputUserPropertiesHash = [ordered]@{ EmailAddress = $userEmailAddress Name = $userName AuthenticationUsername = $userAuthenticationUsername TelephoneMobile = $userMobile Pincode = $userPincode Active = $userEnabled UniqueImportID = $uniqueImportID UserMappedRoles = $userMappedRoles NFCId = $userNFCId DefaultCostCenterIdOrName = $userDefaultCostCenterIdOrName } If ($hasAssignedLicenses -Or $IncludeUsersWithoutAzureADAssignedLicensesOrAssignedPlans) { $outputUser = New-Object PSObject -Property $outputUserPropertiesHash $convertedUsers += $outputUser } } # finishing all, and either put it to process further, or return the result as WhatIf result $syncIncludesUserPincode = $false If ($ADUserPincodePropertyName) { $syncIncludesUserPincode = $true } $syncIncludesUserNFCId = $false If ($ADUserNFCIdPropertyName) { $syncIncludesUserNFCId = $true } # ShouldProcess intercepts WhatIf* --> no need to pass it on If ($PSCmdlet.ShouldProcess("ShouldProcess?")) { If ($DeactivateExistingUsersInSameIntegrationThatAreNotLoaded) { Send-ADUsersToBB -pipelineConvertedADUsers $convertedUsers -BrightBookingApiUrl $BrightBookingApiUrl -BrightBookingApiKey $BrightBookingApiKey -BrightBookingIntegrationName $BrightBookingIntegrationName -UserRoleNameForNewUsers $UserRoleNameForNewUsers -SyncIncludesUserPincode $syncIncludesUserPincode -SyncIncludesUserNFCId $syncIncludesUserNFCId -DeactivateExistingUsersInSameIntegrationThatAreNotLoaded } Else { Send-ADUsersToBB -pipelineConvertedADUsers $convertedUsers -BrightBookingApiUrl $BrightBookingApiUrl -BrightBookingApiKey $BrightBookingApiKey -BrightBookingIntegrationName $BrightBookingIntegrationName -UserRoleNameForNewUsers $UserRoleNameForNewUsers -SyncIncludesUserPincode $syncIncludesUserPincode -SyncIncludesUserNFCId $syncIncludesUserNFCId } } Else { $countConvertedUsers = $convertedUsers | Measure-Object | Select-Object -ExpandProperty Count; Write-Output "============ Test mode (AzureAD) ============" Write-Output "When run in normal mode, it would now process the following $countConvertedUsers users to the API." Write-Output "If you want to run it for real, you should run without the WhatIf parameter." If ($syncIncludesUserPincode) { Write-Output "Sync will process user property '$ADUserPincodePropertyName' as 'PIN code'" } If ($syncIncludesUserNFCId) { Write-Output "Sync will process user property '$ADUserNFCIdPropertyName' as NFC ids" } Return $convertedUsers } } } |