Фотографии профилей пользователей в Office 365

Полезная статья о механизме синхронизации фотографий профилей пользователей в Office 365. В кратце: в Sharepoint Online фотографии профилей синхронизируются с Exchange online и хранятся так же, как в Sharepoint OnPremise — в библиотеке по адресу: https://tenant-my.sharepoint.com/User%20Photos//Profile%20Pictures/

Однако, если у пользователя нет лицензии EXO, возникают проблемы. Командлет Set-UserPhoto в этом случае не работает. Следующий скрипт помогает решить эту проблему.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#Add references to SharePoint client assemblies and authenticate to Office 365 site – required for CSOM
Add-Type -Path ([System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client").location)
Add-Type -Path ([System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.runtime").location)
Add-Type -Path ([System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.UserProfiles").location)
Add-Type -AssemblyName System.Drawing
Function UpdateUserProfile()
{
Param(
[Parameter(Mandatory=$True)]
[String]$targetAcc,

[Parameter(Mandatory=$True)]
[String]$PropertyName,

[Parameter(Mandatory=$False)]
[String]$Value,

[Parameter(Mandatory=$True)]
[String]$SPOAdminPortalUrl,

[Parameter(Mandatory=$True)]
[System.Net.ICredentials]$Creds

)
$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SPOAdminPortalUrl)
$ctx.Credentials = $Creds
$peopleManager = New-Object Microsoft.SharePoint.Client.UserProfiles.PeopleManager($ctx)
$targetAccount = ("i:0#.f|membership|" + $targetAcc)
$peopleManager.SetSingleValueProfileProperty($targetAccount, $PropertyName, $Value)
$ctx.ExecuteQuery()
}

Function UploadImage ()
{
Param(
[Parameter(Mandatory=$True)]
[String]$SiteURL,

[Parameter(Mandatory=$True)]
[String]$User,

[Parameter(Mandatory=$False)]
[String]$Password,

[Parameter(Mandatory=$True)]
[String]$Folder,

[Parameter(Mandatory=$True)]
[String]$SPOAdminPortalUrl

)

#Defualt Image library and Folder value
$DocLibName ="User Photos"
$foldername="Profile Pictures"

#Connect Exchange online

$secstr = New-Object -TypeName System.Security.SecureString
$password.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $User, $secstr
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/?proxyMethod=RPS -Credential $cred -Authentication Basic -AllowRedirection
Import-PSSession $Session

$Securepass = ConvertTo-SecureString $Password -AsPlainText -Force
$Creds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($User,$Securepass)

#Bind to site collection
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$Context.Credentials = $Creds

#Retrieve list
$List = $Context.Web.Lists.GetByTitle($DocLibName)
$Context.Load($List)
$Context.Load($List.RootFolder)
$Context.ExecuteQuery()
$ServerRelativeUrlOfRootFolder = $List.RootFolder.ServerRelativeUrl

$uploadFolderUrl= $ServerRelativeUrlOfRootFolder+"/"+$foldername
$spoimagename = @{"_SThumb" = "48"; "_MThumb" = "72"; "_LThumb" = "200"}
#Upload file
Foreach ($File in (dir $Folder -File))
{

#Upload image into Exchange online
$PictureData = $File.FullName
$Identity=$File.BaseName
Set-UserPhoto -Identity $Identity -PictureData ([System.IO.File]::ReadAllBytes($PictureData)) -Confirm:$false
Write-Host "Exchange online image uploaded successful for" $Identity

$username=$File.BaseName.Replace("@", "_").Replace(".", "_")
$Extension = $File.Extension
Foreach($imagename in $spoimagename.GetEnumerator())
{
#Covert image into different size of image
$img = [System.Drawing.Image]::FromFile((Get-Item $PictureData))
[int32]$new_width = $imagename.Value
[int32]$new_height = $imagename.Value
$img2 = New-Object System.Drawing.Bitmap($new_width, $new_height)
$graph = [System.Drawing.Graphics]::FromImage($img2)
$graph.DrawImage($img, 0, 0, $new_width, $new_height)

#Covert image into memory stream
$stream = New-Object -TypeName System.IO.MemoryStream
$format = [System.Drawing.Imaging.ImageFormat]::Jpeg
$img2.Save($stream, $format)
$streamseek=$stream.Seek(0, [System.IO.SeekOrigin]::Begin)

#Upload image into sharepoint online
$FullFilename=$username+$imagename.Name+$Extension
$ImageRelativeURL="/"+$DocLibName+"/"+$foldername+"/"+$FullFilename
$ModifiedRelativeURL=$ImageRelativeURL.Replace(" ","%20")
[Microsoft.SharePoint.Client.File]::SaveBinaryDirect($Context,$ModifiedRelativeURL, $stream, $true)

}
Write-Host "SharePoint online image uploaded successful for" $Identity
#Change user Profile Property in Sharepoint onlne
$PictureURL=$SiteURL+$DocLibName+"/"+$foldername+"/"+$username+"_MThumb"+$Extension

UpdateUserProfile -targetAcc $Identity -PropertyName PictureURL -Value $PictureURL -SPOAdminPortalUrl $SPOAdminPortalUrl -Creds $Creds

UpdateUserProfile -targetAcc $Identity -PropertyName SPS-PicturePlaceholderState -Value 0 -SPOAdminPortalUrl $SPOAdminPortalUrl -Creds $Creds

UpdateUserProfile -targetAcc $Identity -PropertyName SPS-PictureExchangeSyncState -Value 0 -SPOAdminPortalUrl $SPOAdminPortalUrl -Creds $Creds

UpdateUserProfile -targetAcc $Identity -PropertyName SPS-PictureTimestamp -Value 63605901091 -SPOAdminPortalUrl $SPOAdminPortalUrl -Creds $Creds

Write-Host "Image processed successfully and ready to display for" $Identity
}

}
#Input parameter
$siteUrl="https://tenantname-my.sharepoint.com/"
$username= "admin@tenantname.onmicrosoft.com"
$password= "pass@word1"
$folderpath= "E:\photo"
$SPOAdminPortalUrl = "https://tenantname-admin.sharepoint.com/"

uploadimage -SiteURL $siteUrl -User $username -Password $password -Folder $folderpath -SPOAdminPortalUrl $SPOAdminPortalUrl

Кроме того, данный спкрипт обновляет фото в Delve, и, в результате, они появляются в других местах Office 365. Даже в админке (при условии, что у пользователя есть лицензия Exchange Online).

Перед запуском важно поставить CSOM

Скрипт так же пытается залить фотку в EXO и, при отсутствии у пользователя лицензии Exchange Online, ожидаемо выдает ошибку вида:

1
Не удалось выполнить операцию, поскольку объект "user@domain@nearmedic.ru" не найден в "<a class="" dir="ltr" href="http://am4p190a003dc04.eurp190a003.prod.outlook.com/?fbclid=IwAR0PDFC3LllFljQe2rvls_2MI32pDre1qwyUJnjonhtMTXCjrOZOiLIueIk" target="_blank" rel="nofollow noopener" data-lynx-mode="hover" data-lynx-uri="https://l.facebook.com/l.php?u=http%3A%2F%2FAM4P190A003DC04.EURP190A003.PROD.OUTLOOK.COM%2F%3Ffbclid%3DIwAR0PDFC3LllFljQe2rvls_2MI32pDre1qwyUJnjonhtMTXCjrOZOiLIueIk&amp;h=AT3vuSUtJMuZWfrUJWYWYEOxFXl8jzH6NFLsvWaXw5JT85x2X525XK-p5sTCqyMBY__-sxtDeyBfBed3mjpRZ4CY-8rg1poJo-PyM3-mq0x4S7HmW3CQnNN51PqMIplVM1Rg">AM4P190A003DC04.EURP190A003.PROD.OUTLOOK.COM</a>".