Question
Get-MgGroupMember by display name instead of userID
I am currently in the process of replacing an old script that used Exchange Online Powershell.
The old script was very simple and only performed 2 tasks.
- Downloaded user photos that had custom attribute 3 set to 'employee' + Had a picture from EXO
- upload the downloaded user photo to local AD.
The old script was using an app registration for connecting to exchange online powershell through entra. Now that Get-UserPhoto
along with other cmdlets from EXO Powershell are depricated, I have started learning how to use MSGraph Powershell instead.
I have gotten the user photos to download based on being in the 'Staff' group in Azure + having a photo available to download. However, I have only been able to query users by User ID, then name the download photos as that same User ID. This would solve part 1 of the old script of downloading the photo from azure.
The issue I am running into is with part 2 of the old script. I cant use the photos named with User ID to upload into local AD. Microsoft only allows certain attriubtes when using Set-ADUser -Identity
such as princal name or upn.
How can I get the photos downloaded to download using the displayName, PrincapalName, or UPN of the user instead of the UserID
tl;dr - I need the user photos downloaded from Azure to be named by displayName, userPrincipalName, or UPN.
Old Script
Function LogWrite
{
Param ([string]$logstring)
Add-content $logpath -value $logstring
}
## Get a list of users who have a picture and are an employee ##
Write-Host "Getting a list of users who have a photo and extensionAttribute3 set to employee. This takes a few minutes" |Out-File -Append $logpath
$UsersWithPics = Get-Mailbox -Identity * -ResultSize Unlimited | Where-Object {$_.HasPicture -eq "True" -and $_.CustomAttribute3 -eq "Employee"}
## Download photos from O365
foreach ($Usr in $UsersWithPics) {
If($Usr.UserPrincipalName){
$path = $folderPath+$Usr.UserPrincipalName+".jpg"
$photo = Get-Userphoto -identity $Usr.UserPrincipalName -ErrorAction SilentlyContinue
If($photo.PictureData -ne $null){
[io.file]::WriteAllBytes($path,$photo.PictureData)
Write-Host "Success: Downloaded Pic for $Usr"
LogWrite "Success: Downloaded Pic for $Usr"
}
}
}
## Update Local AD profile pic with ones from O365
###Shows users who have a local ad pic: get-aduser -Filter 'thumbnailPhoto -like "*"' -Properties thumbnailPhoto |Select Name,thumbnailPhoto |Measure-Object
$LocalUsersWithPics = $UsersWithPics | ForEach-Object { $UPN = $_.UserPrincipalName; Get-ADUser -Filter { UserPrincipalName -Eq $UPN } }
foreach ($Usr in $LocalUsersWithPics) {
$photopath = $folderpath+$Usr.UserPrincipalName+".jpg"
$photo = [byte[]](Get-Content $photopath -Encoding byte)
Set-Aduser $Usr.SamAccountName -Replace @{thumbnailPhoto=$photo}
Write-host "Setting Photo: " $photopath "-" "User Getting Photo:" $Usr.SamAccountName
LogWrite "Setting Photo: $photopath - User Getting Photo: $Usr"
}
## Properlly close exchange online connection ##
Disconnect-ExchangeOnline -Confirm:$false
## Remove Logs older than $logLimitDays days ##
Get-childitem -path $logpathDir -Recurse -Force |? { !$_.PSIsContainer -and $_.CreationTime -lt $logLimitDays} |Remove-Item -Force
New Script (In Progress, functionally finds users in the Staff Azure group, checks if they have a photo, then downloads the photo while naming it the long UserID String of text)
# Define a LogWrite function to append logs to a file
Function LogWrite {
Param ([string]$logstring)
Add-content $logpath -value $logstring
}
Write-Host "Getting a list of users who are members of the Staff group. This takes a few minutes" |Out-File -Append $logpath
# Define the group ID for the staff group
$staffGroupId = "*Group ID*"
# Get all members of the staff group
## $groupMembers = Get-MgGroupMember -GroupId $staffGroupId -All -Property "id,displayName,onPremisesExtensionAttributes"
$groupMembers = Get-MgGroupMember -GroupId $staffGroupId -All | Select-Object Id, DisplayName, UserPrincipalName
# Assuming $groupMembers contains the members of the "Staff" group
foreach ($member in $groupMembers) {
$userId = $member.Id
try {
# Define the file path for the photo
$filePath = Join-Path $folderpath "$userid.jpeg"
# Use the Outfile parameter to specify where the photo should be saved
Get-MgUserPhotoContent -UserId $userId -Outfile $filePath -ErrorAction Stop
LogWrite "User $userId photo has been downloaded to $filePath."
} catch {
LogWrite "User $userId does not have a profile photo or an error occurred."
}
}
Things I have tried
I had found a pretty odd workaround to get userprincalname to appear in the query with Get-MgGroupMember
, but I was able to pass the userprincalname through to name the photo
$groupMembers = Get-MgGroupMember -GroupId $staffGroupID -All | Select @{label="DisplayName";expression = {$.AdditionalProperties.displayName} }, Id, @{label="Mail";expression = {$.AdditionalProperties.mail} }, @{label="UserPrincipalName";expression = {$_.AdditionalProperties.userPrincipalName} }
I tried changing the file path and file name using this $filePath = Join-Path $folderpath "$($member.DisplayName).jpeg"
. I continually got the error WARNING: C:\'filepath'\.jpeg already exists. The file will be overridden.