Passaggio all'ora legale 31 marzo 2024 02:00 03:00 sposta avanti l'orologio di 1 ora (si dorme 1 ora in meno)
Con PnP.Powershell è possibile aggiornare un campo people multiutente di SharePoint Online con il comando Set-PnPListItem
PowerShell: Update campo people multiplo
$tenantName = "XXXX"
$siteUrl = "https://$tenantName.sharepoint.com/sites/mioSito"

Connect-PnPOnline -url $siteUrl -Interactive
#Connect-PnPOnline -url $siteUrl -ClientId $clientId -ClientSecret $clientSecret -WarningAction Ignore

# leggo la lista da aggionare tramite la sua url
$list = Get-PnPList -Identity "Lists/ProvaPeople"

# leggo un item tramite il suo id
$item = Get-PnPListItem -List $list -Id 1

# definisco un Array con gli utenti 
$users = @(
    "LeeG@$tenantName.onmicrosoft.com",
    "AlexW@$tenantName.onmicrosoft.com",
    "JohannaL@$tenantName.onmicrosoft.com"
)

# hash table con i campi / valori da aggiornare
$fieldValues = @{"Title" = "Prova $(Get-Date)"; "Users" = $users }

# scrivo i valori nei campi
Set-PnPListItem -List $list -Identity 1 -Values $fieldValues 
come si vede per aggiornare un campo people multiutente è sufficiente passare un array e tutto funziona correttamente
Non ordinatoNon ordinato
ma in alcuni casi...

Casi particolari

Ci sono dei casi particolari in cui l'aggiornamento non va a buon fine, ad esempio se si ordina (Sort-Object) l'array
PowerShell: Esempio con sort
$userValues = $users | sort-object # se faccio il sort da errore in salvataggio

$fieldValues = @{"Title" = "Prova $(Get-Date)"; "Users" = $userValues}

Set-PnPListItem -List $list -Identity 1 -Values $fieldValues
in questo caso, a parità di utenti, viene ritornato questo errore

Set-PnPListItem : The specified user could not be found.
In C:\...\PowerShell\ProveSharePointOnline\Update-PeopleMulti.ps1:58 car:1
+ Set-PnPListItem -List $list -Identity 1 -Values $values
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (:) [Set-PnPListItem], ServerException
+ FullyQualifiedErrorId : EXCEPTION,PnP.PowerShell.Commands.Lists.SetListItem
in pratica il comando sort-object introduce l'errore.

Andando a verificare il tipo di dato ritornato, entrambe le variabili $users e $userValues ritornano object[] e i valori contenuti sono sempre String
PowerShell
PS> $users.GetType().Name        
Object[]
PS> $users.Length           
3
PS> $users[0].GetType().Name
String
PS> $users[1].GetType().Name 
String
PS> $users[2].GetType().Name 
String
PS> $users[3].GetType().Name 
Impossibile chiamare un metodo su un`'espressione con valore null.

       
PS> $userValues.GetType().Name
Object[]
PS> $userValues.Length        
3
PS> $userValues[0].GetType().Name
String
PS> $userValues[1].GetType().Name
String
PS> $userValues[2].GetType().Name
String
PS> $userValues[3].GetType().Name
Impossibile chiamare un metodo su un`'espressione con valore null.
i due oggetti sembrano uguali, ma in realtà non lo sono, il comportamento è inspiegabile.

Lo stesso errore lo si ottiene anche con la Where-Object
PowerShell: Esempio con where
$userValues = $user | Where-Object { $_ -like "a*"} # se filtro da errore in salvataggio

Soluzione

Al momento non ho trovato una soluzione ma solo delle alternative

Alternativa 1

Controllano il codice del comando Set-PnPListItem si vede che, in caso di un array di stringhe, cerca di risolvere il nome facendo l'EnsureUser e poi per scrivere usa l'Id dell'utente (LookupId).

A questo punto si può fare prima l'EnsureUser e passare un array di interi in modo da avere un comportamento stabile e prevedibile
PowerShell
# ottengo il client context
$ctx = Get-PnPContext

# Array per contenere gli Id degli utenti
$userIds = @()

# ciclo sugli oggetti ordinati
$users | sort-object | foreach-Object {
    $web = $ctx.Web
    $user = $web.EnsureUser($_)

    $ctx.Load($user);
    try {
        $ctx.ExecuteQuery();

        # aggiungo l'id utente
        $userIds += $user.Id
    } catch {
        $ErrorMessage = $_.Exception.Message
        Write-Output $ErrorMessage
    }
}

# passo l'array di Id
$fieldValues = @{"Title" = "Prova $(Get-Date)"; "Users" = $userIds }

Set-PnPListItem -List $list -Identity 1 -Values $fieldValues
OrdinatoOrdinato
Questo metodo è il preferibile in quanto controlla anche l'esistenza degli utenti e non passa (catch) quelli inesistenti.
Se nell'array c'è anche un solo utente non valido, tutto l'update fallisce.

Alternativa 2

In caso di sort si può usare il metodo [System.Array]::Sort($users) mentre per simulare la where una if in un foreach
PowerShell: Sort / Where
$userValues = @()

# ordino l'array
[System.Array]::Sort($users)  # se uso direttamente l'array riordinato ottengo un errore in fase di salvataggio

foreach ($item in $users) {
    # eventuale filtro per simulare una where
    if(1 -eq 1) {
        # aggiungo le stringhe all'array
        $userValues += $item
    }
}

$fieldValues = @{"Title" = "Prova $(Get-Date)"; "Users" = $userValues}

Set-PnPListItem -List $list -Identity 1 -Values $fieldValues
Respetto al caso 1, se c'è una stringa relativa ad un utente non esistente, l'update fallisce.
Potrebbe interessarti anche: