Изменение размера фотографии до формата, совместимого с Active Directory - PullRequest
0 голосов
/ 12 ноября 2018

У меня есть функция для изменения размера изображения, которое я получаю из внешней системы, чтобы затем войти в Active Directory для соответствия ограничениям по размеру, однако это, похоже, не работает. Когда я изменяю размер изображения с помощью этого кода, он кажется несовместимым, и попытка установить изображение приводит к ошибкам.

Если я открою это изображение, оно выглядит хорошо. Если я затем сохраню его в редакторе изображений, я смогу затем импортировать его в AD, так что это определенно что-то в этой функции, что не совсем правильно, я думаю, что это связано с кодировкой, но я не знаю достаточно, чтобы исправить это.

Я могу загрузить фотографию (оригинал, слишком большой для AD), используя следующий код:

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

Затем я изменяю его размер и пытаюсь добавить его в AD, что не удается.

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

Это дает мне ошибки от

Set-ADUser: было указано несколько значений для атрибута, который может иметь только одно значение

до

Set-ADUser: Невозможно связаться с сервером. Это может быть связано с тем, что этот сервер не существует, в данный момент не работает или на нем не запущены веб-службы Active Directory.

в зависимости от того, как и где он работает. Я подтвердил, что это не связано с разрешениями или подключением, поскольку я могу записывать другие данные и изображения, не масштабированные в ходе этого процесса.

Если я запишу изображение $ Scaled на диск, я смогу снова сохранить его с помощью редактора изображений, который сделает эту работу. Функция ниже, любая помощь будет высоко ценится!

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()
}
}

1 Ответ

0 голосов
/ 13 ноября 2018

Для AD thumbnailPhoto максимальный размер составляет 96x96 пикселей, поэтому я обычно использую такие функции, чтобы исходное изображение вписывалось в этот маленький квадрат.Вместо того, чтобы использовать функцию, которая требует от вас указывать процент, проще просто использовать эти макс.размеры.

Это вспомогательная функция, которая изменяет размер исходного изображения:

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
}

При необходимости изменяет размеры до указанного $TargetSize и возвращает полный путь и имя файла для этого изображения с измененным размером.(Примечание: возвращаемый путь также может совпадать с исходным изображением, если он вписывается в квадрат $TargetSize)

Следующая функция фактически устанавливает изображение в свойстве AD thumbnailPhoto объекта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
            }
        }
    }
}

Вы называете это с помощью Identity, например Set-ADUserPicture -Identity $SamAccountName -ImageFile $UserImagePath, или с помощью объекта пользователя, который вы получили ранее, используя Get-ADUser командлет, такой как $userObject | Set-ADUserPicture -ImageFile $UserImagePath

Если вы хотитесделать что-то похожее на картинку профиля Office365, то макс.Размеры составляют 648х648 пикселей.Для этого вам необходимо сначала войти в систему, используя что-то вроде этого:

$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

После этого следующая функция установит это изображение аналогично функции для 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
            }
        }
    }
}

Вы вызываете его с помощью идентификатора, например Set-O365UserPicture -Identity $SamAccountName -ImageFile $UserImagePath, или с помощью пользовательского объекта, который вы получили ранее, с помощью командлета Get-ADUser, например $userObject | Set-O365UserPicture -ImageFile $UserImagePath

Для обеих функций Set-ADUserPicture и Set-O365UserPictureЖелательно также добавить переключатель -Verbose.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...