Resizing a photo to a format compatible with Active Directory












0















I have a function to resize an image that I am receiving from an external system to then enter into Active Directory to meet the size restrictions, however it doesn't seem to work. When I resize the image using this code, it doesn't seem to be compatible and attempting to set the image generates errors.



If I open this image, it looks fine. If i then then save it with an image editor, I can then import it into AD, so it's definitely something about this function that isn't quite right, I think it's something encoding related, but I don't know quite enough to fix it.



I can load the photo (the original one that's too big for AD) using the following code:



$original = [system.io.file]::ReadAllBytes('C:original.jpg')


I then resize it and attempt to add it to AD, which fails.



$scaled = ResizeImage -ImageData $original -Percentage 80
Set-ADUser user -Replace @{ thumbnailPhoto=$scaled }


This gives me errors from




Set-ADUser : Multiple values were specified for an attribute that can have only one value




to




Set-ADUser : Unable to contact the server. This may be because this server does not exist, it is currently down, or it does not have the Active Directory Web Services running.




depending on how and where it's run. I've confirmed it's not permissions or connectivity related, as I can write other data and images not scaled through this process.



If i write the the $Scaled image to disk, i can then re-save it with an image editor which makes this work. Function is below, any help would be massively appreciated!



function ResizeImage {
[CmdletBinding()]
Param (
[Parameter(Mandatory)]
[byte]
$ImageData,

[Parameter(Mandatory)]
[double]
$Percentage,

[Parameter()]
[ValidateSet('HighQuality', 'HighSpeed', 'Antialias', 'Default', 'None')]
[string]
$SmoothingMode = "Default",

[Parameter()]
[ValidateSet('Bicubic', 'Bilinear', 'HighQualityBicubic', 'HighQualityBilinear', 'Default', 'High', 'Low', 'NearestNeighbor')]
[string]
$InterpolationMode = "Default",

[Parameter()]
[ValidateSet('HighQuality', 'HighSpeed', 'Half', 'Default', 'None')]
[string]
$PixelOffsetMode = "Default"
)
Begin {
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
}
Process {
$ImageBase64 = [System.Convert]::ToBase64String($ImageData)
$ImageMemory = [System.IO.MemoryStream][System.Convert]::FromBase64String($ImageBase64)
$Bitmap = [System.Drawing.Bitmap][System.Drawing.Image]::FromStream($ImageMemory)
$Product = $Percentage / 100
[int]$NewHeight = $Bitmap.Height * $Product
[int]$NewWidth = $Bitmap.Width * $Product

$NewMemory = [System.IO.MemoryStream]::New()
$NewBitmap = [System.Drawing.Bitmap]::New($NewWidth, $NewHeight)
$NewImage = [System.Drawing.Graphics]::FromImage($NewBitmap)
$NewImage.SmoothingMode = $SmoothingMode
$NewImage.InterpolationMode = $InterpolationMode
$NewImage.PixelOffsetMode = $PixelOffsetMode
$NewImage.DrawImage($Bitmap, $(New-Object -TypeName System.Drawing.Rectangle -ArgumentList 0, 0, $NewWidth, $NewHeight))
$NewBitmap.Save($NewMemory, [System.Drawing.Imaging.ImageFormat]::Jpeg)
[byte]$NewMemory.ToArray()
}
}









share|improve this question























  • Try changing the Set-ADUser argument: @{ thumbnailPhoto=$scaled } -> @{ thumbnailPhoto=,$scaled }

    – Mathias R. Jessen
    Nov 12 '18 at 16:41











  • This gives me an Set-ADUser : Invalid type 'System.Object'. error. I know the setting of the attribute is OK, since if I import an image without scaling it that part works, it's just the run through of the function that seems to change the encoding or the properties of the image in such a way that it's incompatible with AD (or the Set-Aduser function).

    – Dave Green
    Nov 12 '18 at 17:12













  • Then it's most likely just because of a type check, explicitly cast to [byte] and you should be good: @{ thumbnailPhoto = [byte]$scaled }

    – Mathias R. Jessen
    Nov 12 '18 at 17:30











  • Thats crazy! it works in my test, i'll try it in my full test tomorrow and let you know. Do you know why that's needed to work even though i'm using [byte]$NewMemory.ToArray() to emit the object from the function? I can't see any difference in the object when piping both $scaled and [byte]$scaled to get-member.

    – Dave Green
    Nov 12 '18 at 19:05











  • This works over a wide range of images, thank you very much!

    – Dave Green
    Nov 13 '18 at 7:55
















0















I have a function to resize an image that I am receiving from an external system to then enter into Active Directory to meet the size restrictions, however it doesn't seem to work. When I resize the image using this code, it doesn't seem to be compatible and attempting to set the image generates errors.



If I open this image, it looks fine. If i then then save it with an image editor, I can then import it into AD, so it's definitely something about this function that isn't quite right, I think it's something encoding related, but I don't know quite enough to fix it.



I can load the photo (the original one that's too big for AD) using the following code:



$original = [system.io.file]::ReadAllBytes('C:original.jpg')


I then resize it and attempt to add it to AD, which fails.



$scaled = ResizeImage -ImageData $original -Percentage 80
Set-ADUser user -Replace @{ thumbnailPhoto=$scaled }


This gives me errors from




Set-ADUser : Multiple values were specified for an attribute that can have only one value




to




Set-ADUser : Unable to contact the server. This may be because this server does not exist, it is currently down, or it does not have the Active Directory Web Services running.




depending on how and where it's run. I've confirmed it's not permissions or connectivity related, as I can write other data and images not scaled through this process.



If i write the the $Scaled image to disk, i can then re-save it with an image editor which makes this work. Function is below, any help would be massively appreciated!



function ResizeImage {
[CmdletBinding()]
Param (
[Parameter(Mandatory)]
[byte]
$ImageData,

[Parameter(Mandatory)]
[double]
$Percentage,

[Parameter()]
[ValidateSet('HighQuality', 'HighSpeed', 'Antialias', 'Default', 'None')]
[string]
$SmoothingMode = "Default",

[Parameter()]
[ValidateSet('Bicubic', 'Bilinear', 'HighQualityBicubic', 'HighQualityBilinear', 'Default', 'High', 'Low', 'NearestNeighbor')]
[string]
$InterpolationMode = "Default",

[Parameter()]
[ValidateSet('HighQuality', 'HighSpeed', 'Half', 'Default', 'None')]
[string]
$PixelOffsetMode = "Default"
)
Begin {
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
}
Process {
$ImageBase64 = [System.Convert]::ToBase64String($ImageData)
$ImageMemory = [System.IO.MemoryStream][System.Convert]::FromBase64String($ImageBase64)
$Bitmap = [System.Drawing.Bitmap][System.Drawing.Image]::FromStream($ImageMemory)
$Product = $Percentage / 100
[int]$NewHeight = $Bitmap.Height * $Product
[int]$NewWidth = $Bitmap.Width * $Product

$NewMemory = [System.IO.MemoryStream]::New()
$NewBitmap = [System.Drawing.Bitmap]::New($NewWidth, $NewHeight)
$NewImage = [System.Drawing.Graphics]::FromImage($NewBitmap)
$NewImage.SmoothingMode = $SmoothingMode
$NewImage.InterpolationMode = $InterpolationMode
$NewImage.PixelOffsetMode = $PixelOffsetMode
$NewImage.DrawImage($Bitmap, $(New-Object -TypeName System.Drawing.Rectangle -ArgumentList 0, 0, $NewWidth, $NewHeight))
$NewBitmap.Save($NewMemory, [System.Drawing.Imaging.ImageFormat]::Jpeg)
[byte]$NewMemory.ToArray()
}
}









share|improve this question























  • Try changing the Set-ADUser argument: @{ thumbnailPhoto=$scaled } -> @{ thumbnailPhoto=,$scaled }

    – Mathias R. Jessen
    Nov 12 '18 at 16:41











  • This gives me an Set-ADUser : Invalid type 'System.Object'. error. I know the setting of the attribute is OK, since if I import an image without scaling it that part works, it's just the run through of the function that seems to change the encoding or the properties of the image in such a way that it's incompatible with AD (or the Set-Aduser function).

    – Dave Green
    Nov 12 '18 at 17:12













  • Then it's most likely just because of a type check, explicitly cast to [byte] and you should be good: @{ thumbnailPhoto = [byte]$scaled }

    – Mathias R. Jessen
    Nov 12 '18 at 17:30











  • Thats crazy! it works in my test, i'll try it in my full test tomorrow and let you know. Do you know why that's needed to work even though i'm using [byte]$NewMemory.ToArray() to emit the object from the function? I can't see any difference in the object when piping both $scaled and [byte]$scaled to get-member.

    – Dave Green
    Nov 12 '18 at 19:05











  • This works over a wide range of images, thank you very much!

    – Dave Green
    Nov 13 '18 at 7:55














0












0








0








I have a function to resize an image that I am receiving from an external system to then enter into Active Directory to meet the size restrictions, however it doesn't seem to work. When I resize the image using this code, it doesn't seem to be compatible and attempting to set the image generates errors.



If I open this image, it looks fine. If i then then save it with an image editor, I can then import it into AD, so it's definitely something about this function that isn't quite right, I think it's something encoding related, but I don't know quite enough to fix it.



I can load the photo (the original one that's too big for AD) using the following code:



$original = [system.io.file]::ReadAllBytes('C:original.jpg')


I then resize it and attempt to add it to AD, which fails.



$scaled = ResizeImage -ImageData $original -Percentage 80
Set-ADUser user -Replace @{ thumbnailPhoto=$scaled }


This gives me errors from




Set-ADUser : Multiple values were specified for an attribute that can have only one value




to




Set-ADUser : Unable to contact the server. This may be because this server does not exist, it is currently down, or it does not have the Active Directory Web Services running.




depending on how and where it's run. I've confirmed it's not permissions or connectivity related, as I can write other data and images not scaled through this process.



If i write the the $Scaled image to disk, i can then re-save it with an image editor which makes this work. Function is below, any help would be massively appreciated!



function ResizeImage {
[CmdletBinding()]
Param (
[Parameter(Mandatory)]
[byte]
$ImageData,

[Parameter(Mandatory)]
[double]
$Percentage,

[Parameter()]
[ValidateSet('HighQuality', 'HighSpeed', 'Antialias', 'Default', 'None')]
[string]
$SmoothingMode = "Default",

[Parameter()]
[ValidateSet('Bicubic', 'Bilinear', 'HighQualityBicubic', 'HighQualityBilinear', 'Default', 'High', 'Low', 'NearestNeighbor')]
[string]
$InterpolationMode = "Default",

[Parameter()]
[ValidateSet('HighQuality', 'HighSpeed', 'Half', 'Default', 'None')]
[string]
$PixelOffsetMode = "Default"
)
Begin {
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
}
Process {
$ImageBase64 = [System.Convert]::ToBase64String($ImageData)
$ImageMemory = [System.IO.MemoryStream][System.Convert]::FromBase64String($ImageBase64)
$Bitmap = [System.Drawing.Bitmap][System.Drawing.Image]::FromStream($ImageMemory)
$Product = $Percentage / 100
[int]$NewHeight = $Bitmap.Height * $Product
[int]$NewWidth = $Bitmap.Width * $Product

$NewMemory = [System.IO.MemoryStream]::New()
$NewBitmap = [System.Drawing.Bitmap]::New($NewWidth, $NewHeight)
$NewImage = [System.Drawing.Graphics]::FromImage($NewBitmap)
$NewImage.SmoothingMode = $SmoothingMode
$NewImage.InterpolationMode = $InterpolationMode
$NewImage.PixelOffsetMode = $PixelOffsetMode
$NewImage.DrawImage($Bitmap, $(New-Object -TypeName System.Drawing.Rectangle -ArgumentList 0, 0, $NewWidth, $NewHeight))
$NewBitmap.Save($NewMemory, [System.Drawing.Imaging.ImageFormat]::Jpeg)
[byte]$NewMemory.ToArray()
}
}









share|improve this question














I have a function to resize an image that I am receiving from an external system to then enter into Active Directory to meet the size restrictions, however it doesn't seem to work. When I resize the image using this code, it doesn't seem to be compatible and attempting to set the image generates errors.



If I open this image, it looks fine. If i then then save it with an image editor, I can then import it into AD, so it's definitely something about this function that isn't quite right, I think it's something encoding related, but I don't know quite enough to fix it.



I can load the photo (the original one that's too big for AD) using the following code:



$original = [system.io.file]::ReadAllBytes('C:original.jpg')


I then resize it and attempt to add it to AD, which fails.



$scaled = ResizeImage -ImageData $original -Percentage 80
Set-ADUser user -Replace @{ thumbnailPhoto=$scaled }


This gives me errors from




Set-ADUser : Multiple values were specified for an attribute that can have only one value




to




Set-ADUser : Unable to contact the server. This may be because this server does not exist, it is currently down, or it does not have the Active Directory Web Services running.




depending on how and where it's run. I've confirmed it's not permissions or connectivity related, as I can write other data and images not scaled through this process.



If i write the the $Scaled image to disk, i can then re-save it with an image editor which makes this work. Function is below, any help would be massively appreciated!



function ResizeImage {
[CmdletBinding()]
Param (
[Parameter(Mandatory)]
[byte]
$ImageData,

[Parameter(Mandatory)]
[double]
$Percentage,

[Parameter()]
[ValidateSet('HighQuality', 'HighSpeed', 'Antialias', 'Default', 'None')]
[string]
$SmoothingMode = "Default",

[Parameter()]
[ValidateSet('Bicubic', 'Bilinear', 'HighQualityBicubic', 'HighQualityBilinear', 'Default', 'High', 'Low', 'NearestNeighbor')]
[string]
$InterpolationMode = "Default",

[Parameter()]
[ValidateSet('HighQuality', 'HighSpeed', 'Half', 'Default', 'None')]
[string]
$PixelOffsetMode = "Default"
)
Begin {
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
}
Process {
$ImageBase64 = [System.Convert]::ToBase64String($ImageData)
$ImageMemory = [System.IO.MemoryStream][System.Convert]::FromBase64String($ImageBase64)
$Bitmap = [System.Drawing.Bitmap][System.Drawing.Image]::FromStream($ImageMemory)
$Product = $Percentage / 100
[int]$NewHeight = $Bitmap.Height * $Product
[int]$NewWidth = $Bitmap.Width * $Product

$NewMemory = [System.IO.MemoryStream]::New()
$NewBitmap = [System.Drawing.Bitmap]::New($NewWidth, $NewHeight)
$NewImage = [System.Drawing.Graphics]::FromImage($NewBitmap)
$NewImage.SmoothingMode = $SmoothingMode
$NewImage.InterpolationMode = $InterpolationMode
$NewImage.PixelOffsetMode = $PixelOffsetMode
$NewImage.DrawImage($Bitmap, $(New-Object -TypeName System.Drawing.Rectangle -ArgumentList 0, 0, $NewWidth, $NewHeight))
$NewBitmap.Save($NewMemory, [System.Drawing.Imaging.ImageFormat]::Jpeg)
[byte]$NewMemory.ToArray()
}
}






.net powershell active-directory






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 12 '18 at 16:34









Dave GreenDave Green

1




1













  • Try changing the Set-ADUser argument: @{ thumbnailPhoto=$scaled } -> @{ thumbnailPhoto=,$scaled }

    – Mathias R. Jessen
    Nov 12 '18 at 16:41











  • This gives me an Set-ADUser : Invalid type 'System.Object'. error. I know the setting of the attribute is OK, since if I import an image without scaling it that part works, it's just the run through of the function that seems to change the encoding or the properties of the image in such a way that it's incompatible with AD (or the Set-Aduser function).

    – Dave Green
    Nov 12 '18 at 17:12













  • Then it's most likely just because of a type check, explicitly cast to [byte] and you should be good: @{ thumbnailPhoto = [byte]$scaled }

    – Mathias R. Jessen
    Nov 12 '18 at 17:30











  • Thats crazy! it works in my test, i'll try it in my full test tomorrow and let you know. Do you know why that's needed to work even though i'm using [byte]$NewMemory.ToArray() to emit the object from the function? I can't see any difference in the object when piping both $scaled and [byte]$scaled to get-member.

    – Dave Green
    Nov 12 '18 at 19:05











  • This works over a wide range of images, thank you very much!

    – Dave Green
    Nov 13 '18 at 7:55



















  • Try changing the Set-ADUser argument: @{ thumbnailPhoto=$scaled } -> @{ thumbnailPhoto=,$scaled }

    – Mathias R. Jessen
    Nov 12 '18 at 16:41











  • This gives me an Set-ADUser : Invalid type 'System.Object'. error. I know the setting of the attribute is OK, since if I import an image without scaling it that part works, it's just the run through of the function that seems to change the encoding or the properties of the image in such a way that it's incompatible with AD (or the Set-Aduser function).

    – Dave Green
    Nov 12 '18 at 17:12













  • Then it's most likely just because of a type check, explicitly cast to [byte] and you should be good: @{ thumbnailPhoto = [byte]$scaled }

    – Mathias R. Jessen
    Nov 12 '18 at 17:30











  • Thats crazy! it works in my test, i'll try it in my full test tomorrow and let you know. Do you know why that's needed to work even though i'm using [byte]$NewMemory.ToArray() to emit the object from the function? I can't see any difference in the object when piping both $scaled and [byte]$scaled to get-member.

    – Dave Green
    Nov 12 '18 at 19:05











  • This works over a wide range of images, thank you very much!

    – Dave Green
    Nov 13 '18 at 7:55

















Try changing the Set-ADUser argument: @{ thumbnailPhoto=$scaled } -> @{ thumbnailPhoto=,$scaled }

– Mathias R. Jessen
Nov 12 '18 at 16:41





Try changing the Set-ADUser argument: @{ thumbnailPhoto=$scaled } -> @{ thumbnailPhoto=,$scaled }

– Mathias R. Jessen
Nov 12 '18 at 16:41













This gives me an Set-ADUser : Invalid type 'System.Object'. error. I know the setting of the attribute is OK, since if I import an image without scaling it that part works, it's just the run through of the function that seems to change the encoding or the properties of the image in such a way that it's incompatible with AD (or the Set-Aduser function).

– Dave Green
Nov 12 '18 at 17:12







This gives me an Set-ADUser : Invalid type 'System.Object'. error. I know the setting of the attribute is OK, since if I import an image without scaling it that part works, it's just the run through of the function that seems to change the encoding or the properties of the image in such a way that it's incompatible with AD (or the Set-Aduser function).

– Dave Green
Nov 12 '18 at 17:12















Then it's most likely just because of a type check, explicitly cast to [byte] and you should be good: @{ thumbnailPhoto = [byte]$scaled }

– Mathias R. Jessen
Nov 12 '18 at 17:30





Then it's most likely just because of a type check, explicitly cast to [byte] and you should be good: @{ thumbnailPhoto = [byte]$scaled }

– Mathias R. Jessen
Nov 12 '18 at 17:30













Thats crazy! it works in my test, i'll try it in my full test tomorrow and let you know. Do you know why that's needed to work even though i'm using [byte]$NewMemory.ToArray() to emit the object from the function? I can't see any difference in the object when piping both $scaled and [byte]$scaled to get-member.

– Dave Green
Nov 12 '18 at 19:05





Thats crazy! it works in my test, i'll try it in my full test tomorrow and let you know. Do you know why that's needed to work even though i'm using [byte]$NewMemory.ToArray() to emit the object from the function? I can't see any difference in the object when piping both $scaled and [byte]$scaled to get-member.

– Dave Green
Nov 12 '18 at 19:05













This works over a wide range of images, thank you very much!

– Dave Green
Nov 13 '18 at 7:55





This works over a wide range of images, thank you very much!

– Dave Green
Nov 13 '18 at 7:55












1 Answer
1






active

oldest

votes


















0














For an AD thumbnailPhoto the maximum size is 96x96 pixels, so I usually use functions like this to make the original image fit that little square.
Instead of using a function that requires you to give a percentage, it is easier to simply use these max. dimensions.



This is the helper function that resizes the origimal image:



function Shrink-Image {
# helper function to resize an image so it fits inside the given "TargetSize"
# It returns the path and filename of the resized image or the path to the original image if
# that happened to fit inside the "TargetSize" square.
[CmdletBinding()]
param (
[Parameter(Mandatory=$true, Position=0)]
[Alias("FileName")]
[ValidateScript({Test-Path $_ -PathType Leaf})]
[string]$ImagePath,

[Parameter(Mandatory=$true, Position=1)]
[int]$TargetSize,

[int]$Quality = 90
)

Add-Type -AssemblyName "System.Drawing"

$img = [System.Drawing.Image]::FromFile($ImagePath)

# if the original image fits inside the target size, we're done
if ($img.Width -le $TargetSize -and $img.Height -le $TargetSize) {
$img.Dispose()
return $ImagePath
}

# set the encoder quality
$ImageEncoder = [System.Drawing.Imaging.Encoder]::Quality
$encoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1)
$encoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter($ImageEncoder, $Quality)

# set the output codec to jpg
$Codec = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders() | Where-Object {$_.MimeType -eq 'image/jpeg'}

# calculate the image ratio
$ratioX = [double]($TargetSize / $img.Width)
$ratioY = [double]($TargetSize / $img.Height)
if ($ratioX -le $ratioY) { $ratio = $ratioX } else { $ratio = $ratioY }

$newWidth = [int]($img.Width * $ratio)
$newHeight = [int]($img.Height * $ratio)
$newImage = New-Object System.Drawing.Bitmap($newWidth, $newHeight)

$graph = [System.Drawing.Graphics]::FromImage($newImage)
$graph.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic

$graph.Clear([System.Drawing.Color]::White)
$graph.DrawImage($img, 0, 0, $newWidth, $newHeight)

# save the new image as temp file
$OutputPath = [System.IO.Path]::GetTempFileName()

# For safety: a [System.Drawing.Bitmap] does not have a "overwrite if exists" option for the Save() method
if (Test-Path $OutputPath) { Remove-Item $OutputPath -Force }
$newImage.Save($OutputPath, $Codec, $($encoderParams))

$graph.Dispose()
$newImage.Dispose()
$img.Dispose()

return $OutputPath
}


It resizes if needed to the given $TargetSize and returns the full path and filename for this resized image.
(Note: the returned path CAN also be the same as the original image if that happens to fit inside the $TargetSize square)



Next the function to actually set the picture in the AD thumbnailPhoto property of a user:



function Set-ADUserPicture {
[CmdletBinding(DefaultParameterSetName = 'ByName')]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByName', Position = 0)]
[String]$Identity, # This can be: Distinguished Name, objectGUID, objectSid, sAMAccountName

[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByObject', Position = 0)]
[Object]$User, # This is the user object from Get-ADUser

[Parameter(Mandatory = $true, Position = 1)]
[String]$ImageFile
)
if ($PSCmdlet.ParameterSetName -eq 'ByName') {
$User = Get-ADUser -Identity $Identity
}
if ($User) {
Write-Verbose ("Inserting userpicture in Active Directory for user {0}" -f $User.Name)
try {
# create a thumbnail using the original image, and size it down to 96x96 pixels
$pictureFile = Shrink-Image -ImagePath $ImageFile -TargetSize 96
[byte]$pictureData = [System.IO.File]::ReadAllBytes($pictureFile)
$User | Set-ADUser -Replace @{thumbnailPhoto = $pictureData } -ErrorAction Stop
}
catch {
Write-Error "Set-ADUserPicture: $($_.Exception.Message)"
}
finally {
if ($pictureFile -ne $ImageFile) {
# the original image was larger than 96x96 pixels, so we created a temp file. Remove that.
Remove-Item $pictureFile -Force -ErrorAction SilentlyContinue
}
}
}
}


You call it using an Identity like Set-ADUserPicture -Identity $SamAccountName -ImageFile $UserImagePath
or by using the user object you have obtained earlier using the Get-ADUser cmdlet like $userObject | Set-ADUserPicture -ImageFile $UserImagePath



If you want to do something similar for the Office365 profile picture, then the max. dimensions are 648x648 pixels. For that you need to log in first of course using something like this:



$Cred    = Get-Credential -UserName "admin@yourdomain.com" -Message "Please enter admin credentials for Office365"
$Url = "https://outlook.office365.com/powershell-liveid/?proxyMethod=RPS"
$Session = New-PSSession -ConfigurationName "Microsoft.Exchange" -ConnectionUri $Url -Credential $Cred -Authentication Basic -AllowRedirection

Import-PSSession $Session -DisableNameChecking -AllowClobber -WarningAction SilentlyContinue -ErrorAction SilentlyContinue | Out-Null


After that, the next function will set that image similar to the function for the AD thumbnailPhoto:



function Set-O365UserPicture {
[CmdletBinding(DefaultParameterSetName = 'ByName')]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByName', Position = 0)]
[String]$Identity, # This can be: Distinguished Name, objectGUID, objectSid, sAMAccountName

[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByObject', Position = 0)]
[Object]$User, # This is the user object from Get-ADUser

[Parameter(Mandatory = $true, Position = 1)]
[String]$ImageFile
)
if ($PSCmdlet.ParameterSetName -eq 'ByName') {
$User = Get-ADUser -Identity $Identity
}
if ($User) {
Write-Verbose ("Inserting userpicture in Office365 for user {0}" -f $User.Name)
try {
# shrink the original image, and size it down to 648x648 pixels
$pictureFile = Shrink-Image -ImagePath $ImageFile -TargetSize 648
[byte]$pictureData = [System.IO.File]::ReadAllBytes($pictureFile)
$User | Set-UserPhoto -PictureData $pictureData -Confirm:$false -ErrorAction Stop
}
catch {
Write-Error "Set-O365UserPicture: $($_.Exception.Message)"
}
finally {
if ($pictureFile -ne $ImageFile) {
# the original image was larger than 648x648, so we created a temp file. Remove that.
Remove-Item $pictureFile -Force -ErrorAction SilentlyContinue
}
}
}
}


You call it using an Identity like Set-O365UserPicture -Identity $SamAccountName -ImageFile $UserImagePath
or by using the user object you have obtained earlier using the Get-ADUser cmdlet like $userObject | Set-O365UserPicture -ImageFile $UserImagePath



For both functions Set-ADUserPicture and Set-O365UserPicture it is advisable to also add the -Verbose switch.






share|improve this answer
























  • I know for definite that the maximum size for the AD thumbnailphoto is not resolution based, it's size only with a maximum of 100kB. It might be scaled down by client programs, but in my experience Outlook, Skype4Business and every other program supports arbitrary image data. The same actually goes for Office 365, just the limit there is something like 4MB instead.

    – Dave Green
    Nov 14 '18 at 17:36













  • In my situation, I'm actually working solely with bytestream and base64 strings, passing data from one system to another with no disk writes in between for sync. I know they are trivially alterable, but this doesn't really fit as a solution to my question.

    – Dave Green
    Nov 14 '18 at 17:39











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53266417%2fresizing-a-photo-to-a-format-compatible-with-active-directory%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









0














For an AD thumbnailPhoto the maximum size is 96x96 pixels, so I usually use functions like this to make the original image fit that little square.
Instead of using a function that requires you to give a percentage, it is easier to simply use these max. dimensions.



This is the helper function that resizes the origimal image:



function Shrink-Image {
# helper function to resize an image so it fits inside the given "TargetSize"
# It returns the path and filename of the resized image or the path to the original image if
# that happened to fit inside the "TargetSize" square.
[CmdletBinding()]
param (
[Parameter(Mandatory=$true, Position=0)]
[Alias("FileName")]
[ValidateScript({Test-Path $_ -PathType Leaf})]
[string]$ImagePath,

[Parameter(Mandatory=$true, Position=1)]
[int]$TargetSize,

[int]$Quality = 90
)

Add-Type -AssemblyName "System.Drawing"

$img = [System.Drawing.Image]::FromFile($ImagePath)

# if the original image fits inside the target size, we're done
if ($img.Width -le $TargetSize -and $img.Height -le $TargetSize) {
$img.Dispose()
return $ImagePath
}

# set the encoder quality
$ImageEncoder = [System.Drawing.Imaging.Encoder]::Quality
$encoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1)
$encoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter($ImageEncoder, $Quality)

# set the output codec to jpg
$Codec = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders() | Where-Object {$_.MimeType -eq 'image/jpeg'}

# calculate the image ratio
$ratioX = [double]($TargetSize / $img.Width)
$ratioY = [double]($TargetSize / $img.Height)
if ($ratioX -le $ratioY) { $ratio = $ratioX } else { $ratio = $ratioY }

$newWidth = [int]($img.Width * $ratio)
$newHeight = [int]($img.Height * $ratio)
$newImage = New-Object System.Drawing.Bitmap($newWidth, $newHeight)

$graph = [System.Drawing.Graphics]::FromImage($newImage)
$graph.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic

$graph.Clear([System.Drawing.Color]::White)
$graph.DrawImage($img, 0, 0, $newWidth, $newHeight)

# save the new image as temp file
$OutputPath = [System.IO.Path]::GetTempFileName()

# For safety: a [System.Drawing.Bitmap] does not have a "overwrite if exists" option for the Save() method
if (Test-Path $OutputPath) { Remove-Item $OutputPath -Force }
$newImage.Save($OutputPath, $Codec, $($encoderParams))

$graph.Dispose()
$newImage.Dispose()
$img.Dispose()

return $OutputPath
}


It resizes if needed to the given $TargetSize and returns the full path and filename for this resized image.
(Note: the returned path CAN also be the same as the original image if that happens to fit inside the $TargetSize square)



Next the function to actually set the picture in the AD thumbnailPhoto property of a user:



function Set-ADUserPicture {
[CmdletBinding(DefaultParameterSetName = 'ByName')]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByName', Position = 0)]
[String]$Identity, # This can be: Distinguished Name, objectGUID, objectSid, sAMAccountName

[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByObject', Position = 0)]
[Object]$User, # This is the user object from Get-ADUser

[Parameter(Mandatory = $true, Position = 1)]
[String]$ImageFile
)
if ($PSCmdlet.ParameterSetName -eq 'ByName') {
$User = Get-ADUser -Identity $Identity
}
if ($User) {
Write-Verbose ("Inserting userpicture in Active Directory for user {0}" -f $User.Name)
try {
# create a thumbnail using the original image, and size it down to 96x96 pixels
$pictureFile = Shrink-Image -ImagePath $ImageFile -TargetSize 96
[byte]$pictureData = [System.IO.File]::ReadAllBytes($pictureFile)
$User | Set-ADUser -Replace @{thumbnailPhoto = $pictureData } -ErrorAction Stop
}
catch {
Write-Error "Set-ADUserPicture: $($_.Exception.Message)"
}
finally {
if ($pictureFile -ne $ImageFile) {
# the original image was larger than 96x96 pixels, so we created a temp file. Remove that.
Remove-Item $pictureFile -Force -ErrorAction SilentlyContinue
}
}
}
}


You call it using an Identity like Set-ADUserPicture -Identity $SamAccountName -ImageFile $UserImagePath
or by using the user object you have obtained earlier using the Get-ADUser cmdlet like $userObject | Set-ADUserPicture -ImageFile $UserImagePath



If you want to do something similar for the Office365 profile picture, then the max. dimensions are 648x648 pixels. For that you need to log in first of course using something like this:



$Cred    = Get-Credential -UserName "admin@yourdomain.com" -Message "Please enter admin credentials for Office365"
$Url = "https://outlook.office365.com/powershell-liveid/?proxyMethod=RPS"
$Session = New-PSSession -ConfigurationName "Microsoft.Exchange" -ConnectionUri $Url -Credential $Cred -Authentication Basic -AllowRedirection

Import-PSSession $Session -DisableNameChecking -AllowClobber -WarningAction SilentlyContinue -ErrorAction SilentlyContinue | Out-Null


After that, the next function will set that image similar to the function for the AD thumbnailPhoto:



function Set-O365UserPicture {
[CmdletBinding(DefaultParameterSetName = 'ByName')]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByName', Position = 0)]
[String]$Identity, # This can be: Distinguished Name, objectGUID, objectSid, sAMAccountName

[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByObject', Position = 0)]
[Object]$User, # This is the user object from Get-ADUser

[Parameter(Mandatory = $true, Position = 1)]
[String]$ImageFile
)
if ($PSCmdlet.ParameterSetName -eq 'ByName') {
$User = Get-ADUser -Identity $Identity
}
if ($User) {
Write-Verbose ("Inserting userpicture in Office365 for user {0}" -f $User.Name)
try {
# shrink the original image, and size it down to 648x648 pixels
$pictureFile = Shrink-Image -ImagePath $ImageFile -TargetSize 648
[byte]$pictureData = [System.IO.File]::ReadAllBytes($pictureFile)
$User | Set-UserPhoto -PictureData $pictureData -Confirm:$false -ErrorAction Stop
}
catch {
Write-Error "Set-O365UserPicture: $($_.Exception.Message)"
}
finally {
if ($pictureFile -ne $ImageFile) {
# the original image was larger than 648x648, so we created a temp file. Remove that.
Remove-Item $pictureFile -Force -ErrorAction SilentlyContinue
}
}
}
}


You call it using an Identity like Set-O365UserPicture -Identity $SamAccountName -ImageFile $UserImagePath
or by using the user object you have obtained earlier using the Get-ADUser cmdlet like $userObject | Set-O365UserPicture -ImageFile $UserImagePath



For both functions Set-ADUserPicture and Set-O365UserPicture it is advisable to also add the -Verbose switch.






share|improve this answer
























  • I know for definite that the maximum size for the AD thumbnailphoto is not resolution based, it's size only with a maximum of 100kB. It might be scaled down by client programs, but in my experience Outlook, Skype4Business and every other program supports arbitrary image data. The same actually goes for Office 365, just the limit there is something like 4MB instead.

    – Dave Green
    Nov 14 '18 at 17:36













  • In my situation, I'm actually working solely with bytestream and base64 strings, passing data from one system to another with no disk writes in between for sync. I know they are trivially alterable, but this doesn't really fit as a solution to my question.

    – Dave Green
    Nov 14 '18 at 17:39
















0














For an AD thumbnailPhoto the maximum size is 96x96 pixels, so I usually use functions like this to make the original image fit that little square.
Instead of using a function that requires you to give a percentage, it is easier to simply use these max. dimensions.



This is the helper function that resizes the origimal image:



function Shrink-Image {
# helper function to resize an image so it fits inside the given "TargetSize"
# It returns the path and filename of the resized image or the path to the original image if
# that happened to fit inside the "TargetSize" square.
[CmdletBinding()]
param (
[Parameter(Mandatory=$true, Position=0)]
[Alias("FileName")]
[ValidateScript({Test-Path $_ -PathType Leaf})]
[string]$ImagePath,

[Parameter(Mandatory=$true, Position=1)]
[int]$TargetSize,

[int]$Quality = 90
)

Add-Type -AssemblyName "System.Drawing"

$img = [System.Drawing.Image]::FromFile($ImagePath)

# if the original image fits inside the target size, we're done
if ($img.Width -le $TargetSize -and $img.Height -le $TargetSize) {
$img.Dispose()
return $ImagePath
}

# set the encoder quality
$ImageEncoder = [System.Drawing.Imaging.Encoder]::Quality
$encoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1)
$encoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter($ImageEncoder, $Quality)

# set the output codec to jpg
$Codec = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders() | Where-Object {$_.MimeType -eq 'image/jpeg'}

# calculate the image ratio
$ratioX = [double]($TargetSize / $img.Width)
$ratioY = [double]($TargetSize / $img.Height)
if ($ratioX -le $ratioY) { $ratio = $ratioX } else { $ratio = $ratioY }

$newWidth = [int]($img.Width * $ratio)
$newHeight = [int]($img.Height * $ratio)
$newImage = New-Object System.Drawing.Bitmap($newWidth, $newHeight)

$graph = [System.Drawing.Graphics]::FromImage($newImage)
$graph.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic

$graph.Clear([System.Drawing.Color]::White)
$graph.DrawImage($img, 0, 0, $newWidth, $newHeight)

# save the new image as temp file
$OutputPath = [System.IO.Path]::GetTempFileName()

# For safety: a [System.Drawing.Bitmap] does not have a "overwrite if exists" option for the Save() method
if (Test-Path $OutputPath) { Remove-Item $OutputPath -Force }
$newImage.Save($OutputPath, $Codec, $($encoderParams))

$graph.Dispose()
$newImage.Dispose()
$img.Dispose()

return $OutputPath
}


It resizes if needed to the given $TargetSize and returns the full path and filename for this resized image.
(Note: the returned path CAN also be the same as the original image if that happens to fit inside the $TargetSize square)



Next the function to actually set the picture in the AD thumbnailPhoto property of a user:



function Set-ADUserPicture {
[CmdletBinding(DefaultParameterSetName = 'ByName')]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByName', Position = 0)]
[String]$Identity, # This can be: Distinguished Name, objectGUID, objectSid, sAMAccountName

[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByObject', Position = 0)]
[Object]$User, # This is the user object from Get-ADUser

[Parameter(Mandatory = $true, Position = 1)]
[String]$ImageFile
)
if ($PSCmdlet.ParameterSetName -eq 'ByName') {
$User = Get-ADUser -Identity $Identity
}
if ($User) {
Write-Verbose ("Inserting userpicture in Active Directory for user {0}" -f $User.Name)
try {
# create a thumbnail using the original image, and size it down to 96x96 pixels
$pictureFile = Shrink-Image -ImagePath $ImageFile -TargetSize 96
[byte]$pictureData = [System.IO.File]::ReadAllBytes($pictureFile)
$User | Set-ADUser -Replace @{thumbnailPhoto = $pictureData } -ErrorAction Stop
}
catch {
Write-Error "Set-ADUserPicture: $($_.Exception.Message)"
}
finally {
if ($pictureFile -ne $ImageFile) {
# the original image was larger than 96x96 pixels, so we created a temp file. Remove that.
Remove-Item $pictureFile -Force -ErrorAction SilentlyContinue
}
}
}
}


You call it using an Identity like Set-ADUserPicture -Identity $SamAccountName -ImageFile $UserImagePath
or by using the user object you have obtained earlier using the Get-ADUser cmdlet like $userObject | Set-ADUserPicture -ImageFile $UserImagePath



If you want to do something similar for the Office365 profile picture, then the max. dimensions are 648x648 pixels. For that you need to log in first of course using something like this:



$Cred    = Get-Credential -UserName "admin@yourdomain.com" -Message "Please enter admin credentials for Office365"
$Url = "https://outlook.office365.com/powershell-liveid/?proxyMethod=RPS"
$Session = New-PSSession -ConfigurationName "Microsoft.Exchange" -ConnectionUri $Url -Credential $Cred -Authentication Basic -AllowRedirection

Import-PSSession $Session -DisableNameChecking -AllowClobber -WarningAction SilentlyContinue -ErrorAction SilentlyContinue | Out-Null


After that, the next function will set that image similar to the function for the AD thumbnailPhoto:



function Set-O365UserPicture {
[CmdletBinding(DefaultParameterSetName = 'ByName')]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByName', Position = 0)]
[String]$Identity, # This can be: Distinguished Name, objectGUID, objectSid, sAMAccountName

[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByObject', Position = 0)]
[Object]$User, # This is the user object from Get-ADUser

[Parameter(Mandatory = $true, Position = 1)]
[String]$ImageFile
)
if ($PSCmdlet.ParameterSetName -eq 'ByName') {
$User = Get-ADUser -Identity $Identity
}
if ($User) {
Write-Verbose ("Inserting userpicture in Office365 for user {0}" -f $User.Name)
try {
# shrink the original image, and size it down to 648x648 pixels
$pictureFile = Shrink-Image -ImagePath $ImageFile -TargetSize 648
[byte]$pictureData = [System.IO.File]::ReadAllBytes($pictureFile)
$User | Set-UserPhoto -PictureData $pictureData -Confirm:$false -ErrorAction Stop
}
catch {
Write-Error "Set-O365UserPicture: $($_.Exception.Message)"
}
finally {
if ($pictureFile -ne $ImageFile) {
# the original image was larger than 648x648, so we created a temp file. Remove that.
Remove-Item $pictureFile -Force -ErrorAction SilentlyContinue
}
}
}
}


You call it using an Identity like Set-O365UserPicture -Identity $SamAccountName -ImageFile $UserImagePath
or by using the user object you have obtained earlier using the Get-ADUser cmdlet like $userObject | Set-O365UserPicture -ImageFile $UserImagePath



For both functions Set-ADUserPicture and Set-O365UserPicture it is advisable to also add the -Verbose switch.






share|improve this answer
























  • I know for definite that the maximum size for the AD thumbnailphoto is not resolution based, it's size only with a maximum of 100kB. It might be scaled down by client programs, but in my experience Outlook, Skype4Business and every other program supports arbitrary image data. The same actually goes for Office 365, just the limit there is something like 4MB instead.

    – Dave Green
    Nov 14 '18 at 17:36













  • In my situation, I'm actually working solely with bytestream and base64 strings, passing data from one system to another with no disk writes in between for sync. I know they are trivially alterable, but this doesn't really fit as a solution to my question.

    – Dave Green
    Nov 14 '18 at 17:39














0












0








0







For an AD thumbnailPhoto the maximum size is 96x96 pixels, so I usually use functions like this to make the original image fit that little square.
Instead of using a function that requires you to give a percentage, it is easier to simply use these max. dimensions.



This is the helper function that resizes the origimal image:



function Shrink-Image {
# helper function to resize an image so it fits inside the given "TargetSize"
# It returns the path and filename of the resized image or the path to the original image if
# that happened to fit inside the "TargetSize" square.
[CmdletBinding()]
param (
[Parameter(Mandatory=$true, Position=0)]
[Alias("FileName")]
[ValidateScript({Test-Path $_ -PathType Leaf})]
[string]$ImagePath,

[Parameter(Mandatory=$true, Position=1)]
[int]$TargetSize,

[int]$Quality = 90
)

Add-Type -AssemblyName "System.Drawing"

$img = [System.Drawing.Image]::FromFile($ImagePath)

# if the original image fits inside the target size, we're done
if ($img.Width -le $TargetSize -and $img.Height -le $TargetSize) {
$img.Dispose()
return $ImagePath
}

# set the encoder quality
$ImageEncoder = [System.Drawing.Imaging.Encoder]::Quality
$encoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1)
$encoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter($ImageEncoder, $Quality)

# set the output codec to jpg
$Codec = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders() | Where-Object {$_.MimeType -eq 'image/jpeg'}

# calculate the image ratio
$ratioX = [double]($TargetSize / $img.Width)
$ratioY = [double]($TargetSize / $img.Height)
if ($ratioX -le $ratioY) { $ratio = $ratioX } else { $ratio = $ratioY }

$newWidth = [int]($img.Width * $ratio)
$newHeight = [int]($img.Height * $ratio)
$newImage = New-Object System.Drawing.Bitmap($newWidth, $newHeight)

$graph = [System.Drawing.Graphics]::FromImage($newImage)
$graph.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic

$graph.Clear([System.Drawing.Color]::White)
$graph.DrawImage($img, 0, 0, $newWidth, $newHeight)

# save the new image as temp file
$OutputPath = [System.IO.Path]::GetTempFileName()

# For safety: a [System.Drawing.Bitmap] does not have a "overwrite if exists" option for the Save() method
if (Test-Path $OutputPath) { Remove-Item $OutputPath -Force }
$newImage.Save($OutputPath, $Codec, $($encoderParams))

$graph.Dispose()
$newImage.Dispose()
$img.Dispose()

return $OutputPath
}


It resizes if needed to the given $TargetSize and returns the full path and filename for this resized image.
(Note: the returned path CAN also be the same as the original image if that happens to fit inside the $TargetSize square)



Next the function to actually set the picture in the AD thumbnailPhoto property of a user:



function Set-ADUserPicture {
[CmdletBinding(DefaultParameterSetName = 'ByName')]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByName', Position = 0)]
[String]$Identity, # This can be: Distinguished Name, objectGUID, objectSid, sAMAccountName

[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByObject', Position = 0)]
[Object]$User, # This is the user object from Get-ADUser

[Parameter(Mandatory = $true, Position = 1)]
[String]$ImageFile
)
if ($PSCmdlet.ParameterSetName -eq 'ByName') {
$User = Get-ADUser -Identity $Identity
}
if ($User) {
Write-Verbose ("Inserting userpicture in Active Directory for user {0}" -f $User.Name)
try {
# create a thumbnail using the original image, and size it down to 96x96 pixels
$pictureFile = Shrink-Image -ImagePath $ImageFile -TargetSize 96
[byte]$pictureData = [System.IO.File]::ReadAllBytes($pictureFile)
$User | Set-ADUser -Replace @{thumbnailPhoto = $pictureData } -ErrorAction Stop
}
catch {
Write-Error "Set-ADUserPicture: $($_.Exception.Message)"
}
finally {
if ($pictureFile -ne $ImageFile) {
# the original image was larger than 96x96 pixels, so we created a temp file. Remove that.
Remove-Item $pictureFile -Force -ErrorAction SilentlyContinue
}
}
}
}


You call it using an Identity like Set-ADUserPicture -Identity $SamAccountName -ImageFile $UserImagePath
or by using the user object you have obtained earlier using the Get-ADUser cmdlet like $userObject | Set-ADUserPicture -ImageFile $UserImagePath



If you want to do something similar for the Office365 profile picture, then the max. dimensions are 648x648 pixels. For that you need to log in first of course using something like this:



$Cred    = Get-Credential -UserName "admin@yourdomain.com" -Message "Please enter admin credentials for Office365"
$Url = "https://outlook.office365.com/powershell-liveid/?proxyMethod=RPS"
$Session = New-PSSession -ConfigurationName "Microsoft.Exchange" -ConnectionUri $Url -Credential $Cred -Authentication Basic -AllowRedirection

Import-PSSession $Session -DisableNameChecking -AllowClobber -WarningAction SilentlyContinue -ErrorAction SilentlyContinue | Out-Null


After that, the next function will set that image similar to the function for the AD thumbnailPhoto:



function Set-O365UserPicture {
[CmdletBinding(DefaultParameterSetName = 'ByName')]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByName', Position = 0)]
[String]$Identity, # This can be: Distinguished Name, objectGUID, objectSid, sAMAccountName

[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByObject', Position = 0)]
[Object]$User, # This is the user object from Get-ADUser

[Parameter(Mandatory = $true, Position = 1)]
[String]$ImageFile
)
if ($PSCmdlet.ParameterSetName -eq 'ByName') {
$User = Get-ADUser -Identity $Identity
}
if ($User) {
Write-Verbose ("Inserting userpicture in Office365 for user {0}" -f $User.Name)
try {
# shrink the original image, and size it down to 648x648 pixels
$pictureFile = Shrink-Image -ImagePath $ImageFile -TargetSize 648
[byte]$pictureData = [System.IO.File]::ReadAllBytes($pictureFile)
$User | Set-UserPhoto -PictureData $pictureData -Confirm:$false -ErrorAction Stop
}
catch {
Write-Error "Set-O365UserPicture: $($_.Exception.Message)"
}
finally {
if ($pictureFile -ne $ImageFile) {
# the original image was larger than 648x648, so we created a temp file. Remove that.
Remove-Item $pictureFile -Force -ErrorAction SilentlyContinue
}
}
}
}


You call it using an Identity like Set-O365UserPicture -Identity $SamAccountName -ImageFile $UserImagePath
or by using the user object you have obtained earlier using the Get-ADUser cmdlet like $userObject | Set-O365UserPicture -ImageFile $UserImagePath



For both functions Set-ADUserPicture and Set-O365UserPicture it is advisable to also add the -Verbose switch.






share|improve this answer













For an AD thumbnailPhoto the maximum size is 96x96 pixels, so I usually use functions like this to make the original image fit that little square.
Instead of using a function that requires you to give a percentage, it is easier to simply use these max. dimensions.



This is the helper function that resizes the origimal image:



function Shrink-Image {
# helper function to resize an image so it fits inside the given "TargetSize"
# It returns the path and filename of the resized image or the path to the original image if
# that happened to fit inside the "TargetSize" square.
[CmdletBinding()]
param (
[Parameter(Mandatory=$true, Position=0)]
[Alias("FileName")]
[ValidateScript({Test-Path $_ -PathType Leaf})]
[string]$ImagePath,

[Parameter(Mandatory=$true, Position=1)]
[int]$TargetSize,

[int]$Quality = 90
)

Add-Type -AssemblyName "System.Drawing"

$img = [System.Drawing.Image]::FromFile($ImagePath)

# if the original image fits inside the target size, we're done
if ($img.Width -le $TargetSize -and $img.Height -le $TargetSize) {
$img.Dispose()
return $ImagePath
}

# set the encoder quality
$ImageEncoder = [System.Drawing.Imaging.Encoder]::Quality
$encoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1)
$encoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter($ImageEncoder, $Quality)

# set the output codec to jpg
$Codec = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders() | Where-Object {$_.MimeType -eq 'image/jpeg'}

# calculate the image ratio
$ratioX = [double]($TargetSize / $img.Width)
$ratioY = [double]($TargetSize / $img.Height)
if ($ratioX -le $ratioY) { $ratio = $ratioX } else { $ratio = $ratioY }

$newWidth = [int]($img.Width * $ratio)
$newHeight = [int]($img.Height * $ratio)
$newImage = New-Object System.Drawing.Bitmap($newWidth, $newHeight)

$graph = [System.Drawing.Graphics]::FromImage($newImage)
$graph.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic

$graph.Clear([System.Drawing.Color]::White)
$graph.DrawImage($img, 0, 0, $newWidth, $newHeight)

# save the new image as temp file
$OutputPath = [System.IO.Path]::GetTempFileName()

# For safety: a [System.Drawing.Bitmap] does not have a "overwrite if exists" option for the Save() method
if (Test-Path $OutputPath) { Remove-Item $OutputPath -Force }
$newImage.Save($OutputPath, $Codec, $($encoderParams))

$graph.Dispose()
$newImage.Dispose()
$img.Dispose()

return $OutputPath
}


It resizes if needed to the given $TargetSize and returns the full path and filename for this resized image.
(Note: the returned path CAN also be the same as the original image if that happens to fit inside the $TargetSize square)



Next the function to actually set the picture in the AD thumbnailPhoto property of a user:



function Set-ADUserPicture {
[CmdletBinding(DefaultParameterSetName = 'ByName')]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByName', Position = 0)]
[String]$Identity, # This can be: Distinguished Name, objectGUID, objectSid, sAMAccountName

[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByObject', Position = 0)]
[Object]$User, # This is the user object from Get-ADUser

[Parameter(Mandatory = $true, Position = 1)]
[String]$ImageFile
)
if ($PSCmdlet.ParameterSetName -eq 'ByName') {
$User = Get-ADUser -Identity $Identity
}
if ($User) {
Write-Verbose ("Inserting userpicture in Active Directory for user {0}" -f $User.Name)
try {
# create a thumbnail using the original image, and size it down to 96x96 pixels
$pictureFile = Shrink-Image -ImagePath $ImageFile -TargetSize 96
[byte]$pictureData = [System.IO.File]::ReadAllBytes($pictureFile)
$User | Set-ADUser -Replace @{thumbnailPhoto = $pictureData } -ErrorAction Stop
}
catch {
Write-Error "Set-ADUserPicture: $($_.Exception.Message)"
}
finally {
if ($pictureFile -ne $ImageFile) {
# the original image was larger than 96x96 pixels, so we created a temp file. Remove that.
Remove-Item $pictureFile -Force -ErrorAction SilentlyContinue
}
}
}
}


You call it using an Identity like Set-ADUserPicture -Identity $SamAccountName -ImageFile $UserImagePath
or by using the user object you have obtained earlier using the Get-ADUser cmdlet like $userObject | Set-ADUserPicture -ImageFile $UserImagePath



If you want to do something similar for the Office365 profile picture, then the max. dimensions are 648x648 pixels. For that you need to log in first of course using something like this:



$Cred    = Get-Credential -UserName "admin@yourdomain.com" -Message "Please enter admin credentials for Office365"
$Url = "https://outlook.office365.com/powershell-liveid/?proxyMethod=RPS"
$Session = New-PSSession -ConfigurationName "Microsoft.Exchange" -ConnectionUri $Url -Credential $Cred -Authentication Basic -AllowRedirection

Import-PSSession $Session -DisableNameChecking -AllowClobber -WarningAction SilentlyContinue -ErrorAction SilentlyContinue | Out-Null


After that, the next function will set that image similar to the function for the AD thumbnailPhoto:



function Set-O365UserPicture {
[CmdletBinding(DefaultParameterSetName = 'ByName')]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByName', Position = 0)]
[String]$Identity, # This can be: Distinguished Name, objectGUID, objectSid, sAMAccountName

[Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ByObject', Position = 0)]
[Object]$User, # This is the user object from Get-ADUser

[Parameter(Mandatory = $true, Position = 1)]
[String]$ImageFile
)
if ($PSCmdlet.ParameterSetName -eq 'ByName') {
$User = Get-ADUser -Identity $Identity
}
if ($User) {
Write-Verbose ("Inserting userpicture in Office365 for user {0}" -f $User.Name)
try {
# shrink the original image, and size it down to 648x648 pixels
$pictureFile = Shrink-Image -ImagePath $ImageFile -TargetSize 648
[byte]$pictureData = [System.IO.File]::ReadAllBytes($pictureFile)
$User | Set-UserPhoto -PictureData $pictureData -Confirm:$false -ErrorAction Stop
}
catch {
Write-Error "Set-O365UserPicture: $($_.Exception.Message)"
}
finally {
if ($pictureFile -ne $ImageFile) {
# the original image was larger than 648x648, so we created a temp file. Remove that.
Remove-Item $pictureFile -Force -ErrorAction SilentlyContinue
}
}
}
}


You call it using an Identity like Set-O365UserPicture -Identity $SamAccountName -ImageFile $UserImagePath
or by using the user object you have obtained earlier using the Get-ADUser cmdlet like $userObject | Set-O365UserPicture -ImageFile $UserImagePath



For both functions Set-ADUserPicture and Set-O365UserPicture it is advisable to also add the -Verbose switch.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 13 '18 at 16:38









TheoTheo

4,1662520




4,1662520













  • I know for definite that the maximum size for the AD thumbnailphoto is not resolution based, it's size only with a maximum of 100kB. It might be scaled down by client programs, but in my experience Outlook, Skype4Business and every other program supports arbitrary image data. The same actually goes for Office 365, just the limit there is something like 4MB instead.

    – Dave Green
    Nov 14 '18 at 17:36













  • In my situation, I'm actually working solely with bytestream and base64 strings, passing data from one system to another with no disk writes in between for sync. I know they are trivially alterable, but this doesn't really fit as a solution to my question.

    – Dave Green
    Nov 14 '18 at 17:39



















  • I know for definite that the maximum size for the AD thumbnailphoto is not resolution based, it's size only with a maximum of 100kB. It might be scaled down by client programs, but in my experience Outlook, Skype4Business and every other program supports arbitrary image data. The same actually goes for Office 365, just the limit there is something like 4MB instead.

    – Dave Green
    Nov 14 '18 at 17:36













  • In my situation, I'm actually working solely with bytestream and base64 strings, passing data from one system to another with no disk writes in between for sync. I know they are trivially alterable, but this doesn't really fit as a solution to my question.

    – Dave Green
    Nov 14 '18 at 17:39

















I know for definite that the maximum size for the AD thumbnailphoto is not resolution based, it's size only with a maximum of 100kB. It might be scaled down by client programs, but in my experience Outlook, Skype4Business and every other program supports arbitrary image data. The same actually goes for Office 365, just the limit there is something like 4MB instead.

– Dave Green
Nov 14 '18 at 17:36







I know for definite that the maximum size for the AD thumbnailphoto is not resolution based, it's size only with a maximum of 100kB. It might be scaled down by client programs, but in my experience Outlook, Skype4Business and every other program supports arbitrary image data. The same actually goes for Office 365, just the limit there is something like 4MB instead.

– Dave Green
Nov 14 '18 at 17:36















In my situation, I'm actually working solely with bytestream and base64 strings, passing data from one system to another with no disk writes in between for sync. I know they are trivially alterable, but this doesn't really fit as a solution to my question.

– Dave Green
Nov 14 '18 at 17:39





In my situation, I'm actually working solely with bytestream and base64 strings, passing data from one system to another with no disk writes in between for sync. I know they are trivially alterable, but this doesn't really fit as a solution to my question.

– Dave Green
Nov 14 '18 at 17:39


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53266417%2fresizing-a-photo-to-a-format-compatible-with-active-directory%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Full-time equivalent

さくらももこ

13 indicted, 8 arrested in Calif. drug cartel investigation