Get-MgGroupMember по отображаемому имени вместо userID

В настоящее время я занимаюсь заменой старого сценария, использовавшего Exchange Online Powershell.

Старый скрипт был очень простым и выполнял всего 2 задачи.

  1. Загружены фотографии пользователей, у которых для пользовательского атрибута 3 установлено значение «сотрудник» + имеется изображение от EXO.
  2. загрузите загруженную фотографию пользователя в локальный AD.

Старый скрипт использовал регистрацию приложения для подключения к онлайн-обмену 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.

Можете ли вы кратко изложить свой вопрос, пожалуйста?

Santiago Squarzon 19.07.2024 16:57

@SantiagoSquarzon Я только что добавил сводку — tl;dr — мне нужно, чтобы фотографии пользователей, загруженные из Azure, имели имя displayName, userPrincipalName или UPN.

Qwenton 19.07.2024 17:22

Вы имеете в виду имя файла? ты можешь сделать $filePath = Join-Path $folderpath "$($member.DisplayName).jpeg" если да

Santiago Squarzon 19.07.2024 17:36

@SantiagoSquarzon Да, кажется, я нашел это и тоже попробовал. Повторная попытка вызывает некоторые из тех же проблем, которые я наблюдал, спускаясь в эту кроличью нору. Я постоянно получаю сообщение об ошибке, говорящее, что изображение уже существует. Он называет изображения пустыми.jpeg..

Qwenton 19.07.2024 17:42

вы видите отображаемое имя пользователя в $groupMembers?

Santiago Squarzon 19.07.2024 17:50

@SantiagoSquarzon $groupmembers показывает только идентификатор. При извлечении членов группы из Azure с помощью MSGraph я вижу только идентификатор (следовательно, используяmember.Id). DisplayName и UserPrincipalName пусты. Пытаюсь найти способ обойти это.

Qwenton 19.07.2024 18:33
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
Как установить LAMP Stack 1/2 на Azure Linux VM
Как установить LAMP Stack 1/2 на Azure Linux VM
В дополнение к нашему предыдущему сообщению о намерении Azure прекратить поддержку Azure Database для MySQL в качестве единого сервера после 16...
2
6
104
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Судя по отзывам в комментариях, я понимаю, что проблема в том, что 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]). Отсюда я просто собираюсь добавить некоторую логику, чтобы пропускать пользователей, у которых нет фотографии. Затем собираюсь добавить некоторую логику для записи этого в текстовый файл. Спасибо!

Qwenton 22.07.2024 15:24

Другие вопросы по теме