diff --git a/docs/examples/AC_Profile_picture_import.md b/docs/examples/AC_Profile_picture_import.md index c83e8ad..8fa8498 100644 --- a/docs/examples/AC_Profile_picture_import.md +++ b/docs/examples/AC_Profile_picture_import.md @@ -3,11 +3,11 @@ Say you want to bulk import AC profile pictures by dropping them in a folder and naming the image files using a unique identifier. The first the first thing you need to do is authenticate: ```powershell -Connect-Verkada -org_id [your_orgId] -x_api_key (Get-Secret -Name VrkdApiKey -AsPlainText) +Connect-Verkada -x_api_key (Get-Secret -Name VrkdApiKey -AsPlainText) #or for simplicity when not using secrets. -Connect-Verkada -org_id [your_orgId] -x_api_key [your_api_key] +Connect-Verkada -x_api_key [your_api_key] ``` >Then if you've named the image files using the user's **user_id**, like fc6c3648-aa4a-4999-b1a0-a64b81e2cb76.jpg, you can use something like this: @@ -26,7 +26,7 @@ or or ->If you've named the image files using the user's **email**, like some.user@contoso.com.jpg, we will need to find the user_id to set the picture with something like this: +>If you've named the image files using the user's **email**, like `some.user@contoso.com.jpg`, we will need to find the user_id to set the picture with something like this: > >```powershell >Get-ChildItem ~/Documents/AC_profile_pictures | ForEach-Object {$temp = $_; read-VerkadaAccessUsers -version v1 -refresh | Where-Object {$_.email -eq $temp.BaseName} | Set-VerkadaAccessUserProfilePicture -imagePath $temp.FullName; $temp = $null} diff --git a/docs/examples/Merge_duplicate_AC_users.md b/docs/examples/Merge_duplicate_AC_users.md new file mode 100644 index 0000000..e5f15d6 --- /dev/null +++ b/docs/examples/Merge_duplicate_AC_users.md @@ -0,0 +1,110 @@ +# Merge Duplicate AC Users + +Say you want to find duplicate AC users and merge their group membership, cards, and profile pictures. First thing to do is to get an export of the AC users from Command. Then, add a new field to the CSV, **duplicate_userId**. Then we will use that CSV for the import in the script. + +```powershell +Connect-Verkada -x_api_key (Get-Secret -Name VrkdApiKey -AsPlainText) + +#or for simplicity when not using secrets. + +Connect-Verkada -x_api_key [your_api_key] +``` + +After connecting, we will import the user CSV and create our logic for determining duplicate Ids and which user we want to live on. + +```powershell +# import users +$exportedUsers = Import-Csv ~/command-user-export.csv + +# find users with emails that have duplicate users with the same first and last names +# this logic can be changed to meet the needs to determine duplicates +foreach ($user in $exportedUsers){ + if (!([string]::IsNullOrEmpty($user.email))){ + $user.duplicate_userId = $exportedUsers | Where-Object {[string]::IsNullOrEmpty($_.email) -and $_.firstName -ieq $user.firstName -and $_.lastName -ieq $user.lastName} | Select-Object -ExpandProperty userId + } +} +$duplicateSCIMusers = $exportedUsers | Where-Object {!([string]::IsNullOrEmpty($_.duplicate_userId))} +``` + +Once we have the duplicate_userId field added to our CSV the logic below will describe what will be done in the output and perform it in Command. + +```powershell +Start-Transcript -Path ~/transcript_output.txt +$doWork = $false +foreach ($dupe in $duplicateSCIMusers){ + foreach ($dupeId in $dupe.duplicate_userId){ + # determine if duplicate is active + if ($dupe.status -ieq 'active'){ + if (($exportedUsers | Where-Object {$_.userId -eq $dupeId}).status -ieq 'active'){ + write-host "$($dupe.firstName) $($dupe.lastName) - $($dupe.userId) SCIM user is active and has the duplicate account $($dupeId) for us to work on" + $doWork = $true + } else { + write-host "Will do nothing, $($dupe.firstName) $($dupe.lastName) - $($dupe.userId) SCIM user is active but the duplicate account $($dupeId) is $(($exportedUsers | Where-Object {$_.userId -eq $dupeId}).status)." + $doWork = $false + } + } else { + if (($exportedUsers | Where-Object {$_.userId -eq $dupeId}).status -ieq 'active'){ + write-host "$($dupe.firstName) $($dupe.lastName) - $($dupe.userId) SCIM user is $($dupe.status) but the duplicate account $($dupeId) is active, what should we do?" + $doWork = $false + } else { + write-host "Will do nothing, Neither $($dupe.firstName) $($dupe.lastName) - $($dupe.userId) SCIM user or the duplicate account $($dupeId) is active." + $doWork = $false + } + } + + if($doWork){ + # gather all the groups the duplicate is a part of + try { + $groups = Get-VerkadaAccessUser -userId $dupeId -ErrorAction Stop | Select-Object -ExpandProperty access_groups + Write-host "$($dupeId) is part of the following AC Groups: $($groups.name -join ',')" + $scimUserGroups = Get-VerkadaAccessUser -userId $dupe.userId | Select-Object -ExpandProperty access_groups | Select-Object -ExpandProperty group_id + foreach ($group in $groups){ + # determine if the user is already apart of that group + If ($scimUserGroups -contains $group.group_id ){ + Write-Host "$($dupe.firstName) $($dupe.lastName) - $($dupe.userId) is already a part of $($group.name) and doesn't need to be added" + } else { + Write-Host "$($dupe.firstName) $($dupe.lastName) - $($dupe.userId) needs to be added to $($group.name)" + # add user to group if necessary + Set-VerkadaAccessUserGroup -userId $dupe.userId -groupId $group.group_id + } + } + $scimUserGroups = $null + } catch { + $groups = @() + Write-Host "$($dupeId) is not part of any AC groups" + } + + # gather all the cards the duplicate has + $cards = Get-VerkadaAccessUser -userId $dupeId | Select-Object -ExpandProperty cards | Where-Object {$_.active -eq $true} + if ([string]::IsNullOrEmpty($cards)){ + Write-Host "$($dupeId) has no active cards to move" + } else { + Write-host "$($dupeId) has the following cards to move to $($dupe.firstName) $($dupe.lastName) - $($dupe.userId): $($cards.card_number -join ',')" + # assign those cards to the SCIM user + foreach ($card in $cards){ + Add-VerkadaAccessUserCard -userId $dupe.userId -cardType $card.type -cardNumber $card.card_number -facilityCode $card.facility_code -active $true + } + } + + # determine if duplicate has a photo and the SCIM user doesn't + if (!(Get-VerkadaAccessUser -userId $dupe.userId | Select-Object -ExpandProperty has_profile_photo)){ + if (Get-VerkadaAccessUser -userId $dupeId | Select-Object -ExpandProperty has_profile_photo){ + Write-Host "$($dupeId) has a profile photo to copy to $($dupe.firstName) $($dupe.lastName) - $($dupe.userId)" + # get profile photo + Get-VerkadaAccessUserProfilePicture -userId $dupeId -original $true -outPath ~/Downloads/tempPics/ + + # add profile photo to SCIM user + Set-VerkadaAccessUserProfilePicture -userId $dupe.userId -imagePath "~/Downloads/tempPics/$dupeId.jpg" + } + } + # deactivtate the duplicate user + Set-VerkadaAccessUserEndDate -userId $dupeId -endDate (Get-Date) + } + $doWork = $false + + Write-Host "" + } + +} +Stop-Transcript +``` diff --git a/docs/examples/Using_secrets.md b/docs/examples/Using_secrets.md index 44fef27..3b2fd69 100644 --- a/docs/examples/Using_secrets.md +++ b/docs/examples/Using_secrets.md @@ -6,11 +6,11 @@ If you need to retrieve an API key and submit it as plain text. ```powershell $vrkdApiKey = Get-Secret -Name VrkdApiKey -AsPlainText -Connect-Verkada -org_id [your_orgId] -x_api_key $vrkdApiKey +Connect-Verkada -x_api_key $vrkdApiKey #or -Connect-Verkada -org_id [your_orgId] -x_api_key (Get-Secret -Name VrkdApiKey -AsPlainText) +Connect-Verkada -x_api_key (Get-Secret -Name VrkdApiKey -AsPlainText) ``` If you need to retrieve a user password and submit it as a SecureString. diff --git a/verkadaModule/Public/Access/Read-VerkadaAccessUsers.ps1 b/verkadaModule/Public/Access/Read-VerkadaAccessUsers.ps1 index b6f9940..5f80149 100644 --- a/verkadaModule/Public/Access/Read-VerkadaAccessUsers.ps1 +++ b/verkadaModule/Public/Access/Read-VerkadaAccessUsers.ps1 @@ -26,7 +26,7 @@ function Read-VerkadaAccessUsers{ Read-VerkadaAccessUsers -version v1 -refresh This will return all the active access users in an organization with the most recent data available from the Command v1 public API endpoint. The token will be populated from the cache created by Connect-Verkada. #> - [CmdletBinding(PositionalBinding = $true)] + [CmdletBinding(PositionalBinding = $true, DefaultParameterSetName = 'v1')] param ( #This is the graphql query to be submitted (do not use unless you know what you are doing) [Parameter(Position = 1, ParameterSetName = 'legacy')]