hungry_hippo

Powershell GUI Thumbnail update

May 7th, 2015
580
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # Thumbnail-Gui-Update.ps1
  2. # updated 2015-05-08
  3. # Thanks to http://365lab.net/2014/04/21/powershell-gui-application-to-set-thumbnailphoto/
  4. # Thanks to whoever gave me the resize function :)
  5. #
  6. # V1 - Added Resize Function WARNING - Overwrites image
  7. # V2 - Added Get-Creds No Vaildation
  8.  
  9.  
  10.  
  11. if ([threading.thread]::CurrentThread.ApartmentState.ToString() -eq 'MTA') {
  12.     Write-Error "This script requires PowerShell to run in Single-Threaded Apartment. Please run powershell.exe with parameter -STA"
  13.     Exit
  14. }
  15.  
  16. # Import XAML GUI
  17. Add-Type -AssemblyName PresentationFramework
  18. [xml]$XAML = '
  19.   <Window
  20.       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  21.       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  22.       Title="Change AD Photo Thumbnail" Height="312" Width="525" ResizeMode="NoResize">
  23.       <Grid x:Name="list1" Margin="0" Height="280">
  24.            <Grid.ColumnDefinitions>
  25.                    <ColumnDefinition Width="148*"/>
  26.                    <ColumnDefinition Width="86*"/>
  27.                    <ColumnDefinition Width="151*"/>
  28.                    <ColumnDefinition Width="134*"/>
  29.            </Grid.ColumnDefinitions>
  30.            <Grid.RowDefinitions>
  31.                    <RowDefinition Height="53*"/>
  32.                    <RowDefinition Height="142*"/>
  33.                    <RowDefinition Height="85"/>
  34.            </Grid.RowDefinitions>
  35.           <TextBox x:Name="txtSearch" Margin="10,15.04,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" Width="363" Text="Search for user by SamAccountName Here.." Grid.ColumnSpan="3" Height="21.96"/>
  36.           <Button x:Name="btnSearch" Content="Search" HorizontalAlignment="Right" VerticalAlignment="Top" Width="111" Margin="0,15.04,10,0" FontFamily="./#Segoe UI" Grid.Column="3" Height="21.96"/>
  37.           <Label Content="Surname:" Height="26" Margin="3,40,8,0" HorizontalContentAlignment="Right" VerticalAlignment="Top" Grid.Row="1" Grid.Column="1" BorderBrush="Black" BorderThickness="0"/>
  38.           <Label x:Name="lblSn" Content="" Height="26" VerticalAlignment="Top" Margin="10,40,10,0" Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2" BorderBrush="Black" BorderThickness="0"/>
  39.           <Label Content="UsrPName:" Height="25" Margin="3,71,8,0" HorizontalContentAlignment="Right" VerticalAlignment="Top" Grid.Row="1" Grid.Column="1" BorderBrush="Black" BorderThickness="0"/>
  40.           <Label x:Name="lblUPN" Content="" Height="25" VerticalAlignment="Top" Margin="10,71,10,0" Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2" BorderBrush="Black" BorderThickness="0"/>
  41.           <Label Content="Firstname:" Height="26" Margin="3,9,8,0" HorizontalContentAlignment="Right" VerticalAlignment="Top" Grid.Row="1" Grid.Column="1" BorderBrush="Black" BorderThickness="0"/>
  42.           <Label x:Name="lblGivenName" Content="" Height="26" VerticalAlignment="Top" Margin="10,9,10,0" Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2" BorderBrush="Black" BorderThickness="0"/>
  43.           <Label Content="DName:" Height="25" Margin="3,101,8,0" HorizontalContentAlignment="Right" VerticalAlignment="Top" Grid.Row="1" Grid.Column="1" BorderBrush="Black" BorderThickness="0"/>
  44.           <Label x:Name="lblDN" Content="" Height="25" VerticalAlignment="Top" Margin="10,101,10,0" Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2" BorderBrush="Black" BorderThickness="0"/>
  45.           <Border BorderBrush="Black" BorderThickness="1" Margin="10,9,10,16" Grid.Row="1">
  46.                            <Image x:Name="imgThumb" Margin="2" Grid.Row="1" OpacityMask="#FFF0F0F0"/>
  47.           </Border>
  48.           <Button x:Name="btnRemoveImg" Content="Remove photo" Height="32" Margin="17,12,19,0" VerticalAlignment="Top" IsEnabled="False" BorderThickness="1" Grid.Row="2"/>
  49.           <Button x:Name="btnImg" Content="Select photo" Height="32" Margin="17,12,19,0" VerticalAlignment="Top" IsEnabled="False" BorderThickness="1" Grid.Row="2" Grid.Column="2"/>
  50.           <Button x:Name="btnApply" Content="Apply" HorizontalAlignment="Right" Margin="0,12,10,0" Width="111" IsEnabled="False" Grid.Row="2" Grid.Column="3" Height="32" VerticalAlignment="Top"/>
  51.           <StatusBar Height="30" Grid.Row="2" VerticalAlignment="Bottom" Grid.ColumnSpan="4" Background="#FFF0F0F0" Margin="0">
  52.                    <Label x:Name="lblStatus" Content="Ready.." Width="509" FontSize="10.667" VerticalAlignment="Top"/>
  53.           </StatusBar>
  54.       </Grid>
  55.   </Window>
  56. '
  57.  
  58.  
  59.  
  60. #
  61. # Resize to 100x100 max
  62. #
  63.  
  64.  
  65. function resize-image{
  66. Param ( [Parameter(Mandatory=$True)] [ValidateNotNull()] $imageSource,
  67. [Parameter(Mandatory=$True)] [ValidateNotNull()] $imageTarget,
  68. [Parameter(Mandatory=$true)][ValidateNotNull()] $quality )
  69.  
  70. if (!(Test-Path $imageSource)){throw( "Cannot find the source image")}
  71. if(!([System.IO.Path]::IsPathRooted($imageSource))){throw("please enter a full path for your source path")}
  72. if(!([System.IO.Path]::IsPathRooted($imageTarget))){throw("please enter a full path for your target path")}
  73. if ($quality -lt 0 -or $quality -gt 100){throw( "quality must be between 0 and 100.")}
  74.  
  75. [void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
  76. $bmp = [System.Drawing.Image]::FromFile($imageSource)
  77.  
  78. #hardcoded canvas size...
  79. $canvasWidth = 100.0
  80. $canvasHeight = 100.0
  81.  
  82. #Encoder parameter for image quality
  83. $myEncoder = [System.Drawing.Imaging.Encoder]::Quality
  84. $encoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1)
  85. $encoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter($myEncoder, $quality)
  86. # get codec
  87. $myImageCodecInfo = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders()|where {$_.MimeType -eq 'image/jpeg'}
  88.  
  89. #compute the final ratio to use
  90. $ratioX = $canvasWidth / $bmp.Width;
  91. $ratioY = $canvasHeight / $bmp.Height;
  92. $ratio = $ratioY
  93. if($ratioX -le $ratioY){
  94. $ratio = $ratioX
  95. }
  96.  
  97. #create resized bitmap
  98. $newWidth = [int] ($bmp.Width*$ratio)
  99. $newHeight = [int] ($bmp.Height*$ratio)
  100. $bmpResized = New-Object System.Drawing.Bitmap($newWidth, $newHeight)
  101. $graph = [System.Drawing.Graphics]::FromImage($bmpResized)
  102.  
  103. $graph.Clear([System.Drawing.Color]::White)
  104. $graph.DrawImage($bmp,0,0 , $newWidth, $newHeight)
  105.  
  106. #save to file
  107. $bmpResized.Save($imageTarget,$myImageCodecInfo, $($encoderParams))
  108. $bmpResized.Dispose()
  109. $bmp.Dispose()
  110.  
  111. }
  112.  
  113. $global:userinfo = @{
  114.     dn = $null
  115.     photo = [byte[]]$null
  116. }
  117.  
  118. function Invoke-FileBrowser {
  119.     param([string]$Title,[string]$Directory,[string]$Filter="jpeg (*.jpg)|*.jpg")
  120.     [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
  121.     $FileBrowser = New-Object System.Windows.Forms.OpenFileDialog
  122.     $FileBrowser.InitialDirectory = $Directory
  123.     $FileBrowser.Filter = $Filter
  124.     $FileBrowser.Title = $Title
  125.     $Show = $FileBrowser.ShowDialog()
  126.     If ($Show -eq "OK") { Return $FileBrowser.FileName }
  127. }
  128. function Get-LDAPUsers($sam) {
  129.     # Msg
  130.     $lblStatus.Content = "Searching..."
  131.  
  132.     # Go
  133.     $activeDomain = New-Object DirectoryServices.DirectoryEntry
  134.     $domain = $activeDomain.distinguishedName
  135.     $searcher = [System.DirectoryServices.DirectorySearcher]"[ADSI]LDAP://$domain"
  136.     $searcher.filter = "(&(samaccountname=$sam)(objectClass=user)(objectClass=person))"
  137.     $result = $searcher.findall()
  138.    
  139.     # Interpret results  
  140.     if ($result.count -gt 1) {
  141.         $lblStatus.Content = "More than one user found. Please refine your search."
  142.     } elseif ($result.count -eq 1) {
  143.         # Get info
  144.         $result = $searcher.findone().getDirectoryEntry()
  145.         [pscustomobject]@{
  146.             UserPrincipalName= $result.userprincipalname[0]
  147.             DistinguishedName= $result.distinguishedname[0]
  148.             samAccountName = $result.samaccountname[0]
  149.             Givenname = $result.givenname[0]
  150.             Surname = $result.sn[0]
  151.             ThumbnailPhoto = $result.thumbnailphoto
  152.         }
  153.  
  154.         # Msg
  155.         $lblStatus.Content = "Found user succesfully."
  156.     } else {
  157.         $lblStatus.Content = "No users found. Please refine your search."
  158.     }
  159. }
  160. function Update-WPFForm($sam) {
  161.    $selecteduser = Get-LDAPUsers $sam
  162.    if ($selecteduser) {
  163.         $global:userinfo.dn = $selecteduser.DistinguishedName
  164.         $global:userinfo.photo = [byte[]]$($selecteduser.thumbnailphoto)
  165.        
  166.         $lblGivenName.Content = $selecteduser.GivenName
  167.         $lblSN.Content = $selecteduser.SurName
  168.         $lblUPN.Content = $selecteduser.UserPrincipalName
  169.         $txtSearch.Text = $selecteduser.SamAccountName
  170.         $imgThumb.Source = $global:userinfo.photo
  171.         $btnImg.IsEnabled = $true
  172.         $btnRemoveImg.IsEnabled = $true
  173.  
  174.         # Check and concat the DN
  175.         $dn = $global:userinfo.dn
  176.         if (($global:userinfo.dn).length -gt 38) {
  177.             $dn = "$(($dn).substring(0,38)).."
  178.             $lblDN.Content = $dn
  179.             $lblDN.Tooltip = $global:userinfo.dn
  180.         } else {
  181.             $lblDN.Content = $dn
  182.         }
  183.     }
  184. }
  185.  
  186. #region GUI
  187.     $reader=(New-Object System.Xml.XmlNodeReader $xaml)
  188.     $window=[Windows.Markup.XamlReader]::Load($reader)
  189.  
  190.     $btnSearch = $window.FindName("btnSearch")
  191.     $btnImg = $window.FindName("btnImg")
  192.     $btnRemoveImg = $window.FindName("btnRemoveImg")
  193.     $btnApply = $window.FindName("btnApply")
  194.     $txtSearch = $window.FindName("txtSearch")
  195.     $lblGivenName = $window.FindName("lblGivenName")
  196.     $lblSn = $window.FindName("lblSn")
  197.     $lblUPN = $window.FindName("lblUPN")
  198.     $lblDN = $window.FindName("lblDN")
  199.     $imgThumb = $window.FindName("imgThumb")
  200.     $lblStatus = $window.FindName("lblStatus")
  201. #endregion GUI
  202.  
  203. #region Events
  204.     #region btnSearchClick
  205.         $btnSearch_click = $btnSearch.add_Click
  206.         $btnSearch_click.Invoke({
  207.             Update-WPFForm($txtSearch.Text)
  208.         })
  209.     #endregion btnSearchClick
  210.     #region btnImgClick
  211.         $btnImg_click = $btnImg.add_Click
  212.         $btnImg_click.Invoke({
  213.             $file = Invoke-FileBrowser -Title "Choose a thumbnail photo" -Filter "Jpeg pictures (*.jpg)|*.jpg"
  214.             if ($file) {
  215.                 if ((Get-Item $file).length -gt 10kB) {
  216.                     $lblStatus.Content = "resizing image"
  217.  
  218.  
  219.                     #
  220.                     # sorry about this, but wasnt sure how to force overwrite using resize-image funciton
  221.                     #
  222.  
  223.                         $newName = $file +"_temp.jpg"
  224.                         REsize-Image  $file $newName 95
  225.                         write-host resize $file
  226.                         move $newName $file -Force
  227.  
  228.                     $global:userinfo.photo = [byte[]](Get-Content $file -encoding byte)
  229.                     $imgThumb.Source = $global:userinfo.photo
  230.                     $btnApply.IsEnabled = $true
  231.  
  232.                     $lblStatus.Content = "resized and ready for update - click apply"
  233.  
  234.                 } else {
  235.                     $global:userinfo.photo = [byte[]](Get-Content $file -encoding byte)
  236.                     $imgThumb.Source = $global:userinfo.photo
  237.                     $btnApply.IsEnabled = $true
  238.                 }
  239.             }
  240.         })
  241.     #endregion btnImgClick
  242.    
  243.     #region btnRemoveImage
  244.         $btnRemoveImg_click = $btnRemoveImg.add_Click
  245.         $btnRemoveImg_click.Invoke({
  246.             $username = $creds.username
  247.             $password = $creds.GetNetworkCredential().password
  248.             $user = New-Object DirectoryServices.DirectoryEntry("LDAP://$($global:userinfo.dn)",$username,$password)
  249.             $user.putex(1,"thumbnailPhoto",0)
  250.             $user.setinfo()
  251.             $btnApply.IsEnabled = $false
  252.             Write-Verbose "User $($global:userinfo.dn) updated - image removed."
  253.             Update-WPFForm($txtSearch.Text)
  254.             $lblStatus.Content = "Image Removed  - search again or close"
  255.         })
  256.     #endregion btnRemoveImage
  257.    
  258.     #region btnApplyClick
  259.         $btnApply_click = $btnApply.add_Click
  260.         $btnApply_click.Invoke({
  261.             $username = $creds.username
  262.             $password = $creds.GetNetworkCredential().password
  263.             $user = New-Object DirectoryServices.DirectoryEntry("LDAP://$($global:userinfo.dn)",$username,$password)
  264.             $user.put("thumbnailPhoto", $global:userinfo.photo)
  265.             $user.setinfo()
  266.             $btnApply.IsEnabled = $false
  267.             Write-Verbose "User $($global:userinfo.dn) updated."
  268.             $lblStatus.Content = "Applied - search again or close"
  269.         })
  270.     #endregion btnApplyClick
  271.     #region textChange
  272.         $txtSearch_Change = $txtSearch.add_KeyDown
  273.         $txtSearch_Change.Invoke({
  274.             if ($_.Key -ieq 'Return') {
  275.                 Update-WPFForm($txtSearch.Text)
  276.             }
  277.         })
  278.     #endregion textChange
  279.     #region clearOnClick
  280.         $txtSearch_click = $txtSearch.add_GotFocus
  281.         $txtSearch_click.Invoke({
  282.             $txtSearch.Clear()
  283.         })
  284.     #endregion
  285. #endregion Events
  286.  
  287. $creds=Get-Credential # -Message "Enter Admin Password"
  288. $window.ShowDialog() | Out-Null
RAW Paste Data