We recently upgraded to Lync 2015 (aka Skype for Business). One feature which frustrated me was the group conversations; you can either see people’s names; in which case they’re listed in such a way as to use up a large amount of screen space, or you can see people’s photos/thumbnails, which is great except when most people don’t have their photo associated with their account.
To resolve this quickly I came up with the below script which:
- Gets all AD users under a given OU / SearchBase
- Filters for those without a thumbnail photo associated
- Determines the users’ initials
- Creates a JPG of their initials
- Assigns this JPG as their thumbnail image
Thus giving an easier way to tell who you’re talking to until they get around to uploading a photo.
NB: The below script is currently untested as I don’t have sufficient rights to update AD / will have to wait for our infrastructure team to assist there… but those parts that I could test have been tested.
Add-Type -AssemblyName System.Drawing Add-Type -AssemblyName System.IO Add-Type -AssemblyName Microsoft.ActiveDirectory.Management Import-Module ActiveDirectory function Convert-InitialsToJpegImageByteArray { [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [string]$Initials , [Parameter(Mandatory = $false)] [int]$WidthInPixels = 96 #Ref https://technet.microsoft.com/en-gb/library/jj688150.aspx: decided not to go 648x648 just for text , [Parameter(Mandatory = $false)] [int]$HeightInPixels = 96 , [Parameter(Mandatory = $false)] [System.Drawing.Font]$Font = (new-object System.Drawing.Font ('Proxima Nova Alt',32, [System.Drawing.FontStyle]::Bold)) , [Parameter(Mandatory = $false)] [System.Drawing.Color]$BackgroundColor = "#FF000434" #ARGB Colors , [Parameter(Mandatory = $false)] [System.Drawing.Color]$ForegroundColor = "#FF0099D8" ) process { [System.Drawing.Bitmap]$bmp = new-object System.Drawing.Bitmap ($widthInPixels, $heightInPixels) [System.Drawing.Brush]$BrushBg = (new-object System.Drawing.SolidBrush ($BackgroundColor)) [System.Drawing.Brush]$brushFg = (new-object System.Drawing.SolidBrush ($ForegroundColor)) [System.Drawing.Graphics]$graphics = [System.Drawing.Graphics]::FromImage($bmp) $graphics.FillRectangle($brushBg,0,0,$bmp.Width,$bmp.Height) $graphics.DrawString($initials,$font,$brushFg,15,18) $graphics.Dispose() [System.IO.MemoryStream]$stream = new-object System.IO.MemoryStream $bmp.Save($stream,[System.Drawing.Imaging.ImageFormat]::Jpeg) $stream.Close() $stream.ToArray() $stream.Dispose() } } function Get-AdUserInitials { [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [Microsoft.ActiveDirectory.Management.ADUser]$User ) process { #$User = Get-ADUser $Identity #we could do parameter sets to allow passing only an identity $User | select-object @{Name='User';Expression={$User}}, @{Name='Initials';Expression={("{0}{1}" -f ("{0}?" -f $_.GivenName)[0],("{0}?" -f $_.Surname)[0]).ToUpperInvariant()}} } } function Get-AdUsersWithNoThumbnail { [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [string]$SearchBase , [Parameter(Mandatory = $false)] [ValidateSet('Base','OneLevel','Subtree')] [string]$SearchScope = 'Subtree' , [Parameter(Mandatory = $false)] [string]$Filter = {Enabled -eq $true} ) process { get-aduser -filter {Enabled -eq $true} -SearchBase $SearchBase -SearchScope $SearchScope -Properties thumbnailPhoto | ?{!$_.thumbnailPhoto} } } @('OU=UK,DC=myCompany,DC=com') ` | Get-AdUsersWithNoThumbnail ` | Get-AdUserInitials ` | %{ $User = $_.User [byte[]]$Image = $_.Initials | Convert-InitialsToJpegImageByteArray Set-Aduser $user -replace @{thumbnailPhoto=$Image} }