Aggiornare un campo pepole multi user con Set-PnPListItem (SharePoint OnLine)
Con PnP.Powershell è possibile aggiornare un campo people multiutente di SharePoint Online con il comando Set-PnPListItem
come si vede per aggiornare un campo people multiutente è sufficiente passare un array e tutto funziona correttamentema in alcuni casi...
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
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
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: 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
Casi particolari
Ci sono dei casi particolari in cui l'aggiornamento non va a buon fine, ad esempio se si ordina (Sort-Object) l'arrayPowerShell: 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
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
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.
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 alternativeAlternativa 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
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.
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 foreachPowerShell: 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.