В настоящее время я занимаюсь заменой старого сценария, использовавшего Exchange Online Powershell.
Старый скрипт был очень простым и выполнял всего 2 задачи.
Старый скрипт использовал регистрацию приложения для подключения к онлайн-обмену PowerShell через entra. Теперь, когда Get-UserPhoto
и другие командлеты из EXO Powershell устарели, я начал вместо этого учиться использовать MSGraph Powershell.
Я получил фотографии пользователей для загрузки, поскольку нахожусь в группе «Сотрудники» в Azure + у меня есть фотография, доступная для загрузки. Однако мне удавалось запрашивать пользователей только по идентификатору пользователя, а затем называть загружаемые фотографии тем же идентификатором пользователя. Это решило бы часть 1 старого скрипта загрузки фото с лазури.
Проблема, с которой я столкнулся, связана со второй частью старого сценария. Я не могу использовать фотографии, названные с помощью идентификатора пользователя, для загрузки в локальный AD. Microsoft разрешает использовать только определенные атрибуты при использовании Set-ADUser -Identity
, например имя принципала или upn.
Как я могу загрузить фотографии для загрузки, используя displayName, PrincapalName или UPN пользователя вместо UserID
tl;dr — мне нужно, чтобы фотографии пользователей, загруженные из Azure, имели имя displayName, userPrincipalName или UPN.
Старый сценарий
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
Новый скрипт (в стадии выполнения, функционально находит пользователей в группе Azure Staff, проверяет, есть ли у них фотография, затем загружает фотографию, называя ее длинной текстовой строкой UserID)
# 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."
}
}
Вещи, которые я пробовал
Я нашел довольно странный обходной путь, позволяющий отображать имя пользователя в запросе с Get-MgGroupMember
, но мне удалось передать имя пользователя, чтобы назвать фотографию.
$groupMembers = Get-MgGroupMember -GroupId $staffGroupID -All | Select @{label = "DisplayName";expression = {$.AdditionalProperties.displayName} }, Id, @{label = "Mail";expression = {$.AdditionalProperties.mail} }, @{label = "UserPrincipalName";expression = {$_.AdditionalProperties.userPrincipalName} }
Я попробовал изменить путь к файлу и имя файла, используя это $filePath = Join-Path $folderpath "$($member.DisplayName).jpeg"
. Постоянно получаю ошибку WARNING: C:\'filepath'\.jpeg already exists. The file will be overridden.
@SantiagoSquarzon Я только что добавил сводку — tl;dr — мне нужно, чтобы фотографии пользователей, загруженные из Azure, имели имя displayName, userPrincipalName или UPN.
Вы имеете в виду имя файла? ты можешь сделать $filePath = Join-Path $folderpath "$($member.DisplayName).jpeg"
если да
@SantiagoSquarzon Да, кажется, я нашел это и тоже попробовал. Повторная попытка вызывает некоторые из тех же проблем, которые я наблюдал, спускаясь в эту кроличью нору. Я постоянно получаю сообщение об ошибке, говорящее, что изображение уже существует. Он называет изображения пустыми.jpeg..
вы видите отображаемое имя пользователя в $groupMembers
?
@SantiagoSquarzon $groupmembers
показывает только идентификатор. При извлечении членов группы из Azure с помощью MSGraph я вижу только идентификатор (следовательно, используяmember.Id). DisplayName и UserPrincipalName пусты. Пытаюсь найти способ обойти это.
Судя по отзывам в комментариях, я понимаю, что проблема в том, что Get-MgGroupMember
не дает вам displayName
или userPrincipalName
пользователя, чтобы вы могли использовать одно из этих значений в качестве имени файла. Я лично не в курсе, как ведет себя этот командлет, я не использую ни один командлет из модуля Graph, ни один из них ничего не стоит, кроме Invoke-MgGraphRequest
для прямых вызовов API.
Если вы запросите напрямую конечную точку Список членов группы , вы получите эти 2 обязательных свойства. Вы также можете использовать так называемое Приведение OData , чтобы получить только членов группы, которые имеют тип microsoft.graph.user
, чтобы сделать запрос более эффективный. Оттуда для каждого участника пользователя вы можете вызвать в конечную точку Get ProfilePhoto, чтобы извлечь изображение профиля.
Вот как будет выглядеть код:
$staffGroupId = 'xxxx-xxxx-xxxx-xxxx'
$uri = "v1.0/groups/$staffGroupId/members/microsoft.graph.user?`$select=id, displayName, userPrincipalName"
do {
$groupMembers = Invoke-MgGraphRequest GET $uri
$uri = $groupMembers['@odata.nextLink']
foreach ($user in $groupMembers['value']) {
$upn = $user['userPrincipalName'] # here you can choose `$user['displayName']` too
$invokeMgGraphRequestSplat = @{
OutputFilePath = "$upn.jpg"
Method = 'GET'
Uri = "v1.0/users/$upn/photo/`$value"
}
Invoke-MgGraphRequest @invokeMgGraphRequestSplat
}
}
while ($uri)
Это сработало! Все изображения загружаются в формате JPG и используют UPN в качестве имени файла ([email protected]). Отсюда я просто собираюсь добавить некоторую логику, чтобы пропускать пользователей, у которых нет фотографии. Затем собираюсь добавить некоторую логику для записи этого в текстовый файл. Спасибо!
Можете ли вы кратко изложить свой вопрос, пожалуйста?