Aktionen

Foto im Active Directory hinterlegen und bei Benutzeranmeldung anzeigen

Aus znilwiki

Changelog:

  • 28.05.2015: Erste Version
  • 01.06.2015: Version 1.0.0.5: Erkennt ob das Bild im AD als .PNG oder .JPEG gespeichert ist und speichert es mit der entsprechenden Dateiendung



1 Vorwort

Bei der Anmeldung an Windows wird seit Windows Vista ein kleines Bildchen gezeigt - welches er sich auch selbst setzen kann:

UserAccountPictures-001.png


Die Bilder der Benutzer liegen dabei immer lokal unter

C:\ProgramData\Microsoft\User Account Pictures

UserAccountPictures-002.png

Da liegen auch schon 2 Dateien, die

user.bmp

wird dabei immer für neue Benutzer genommen wenn dieser sich kein eigenes Bild setzt.
Wenn Ihr also dieses Bild austauscht (Bitte mit gleichen Abmessungen und Format etc.) würde alle Benutzer dieses Bild erhalten.



2 Foto im Active Directory hinterlegen

Nun gibt es seit Windows Server 2008 und der dazu gehörigen Active Directory Version die Möglichkeit bei jedem Benutzer 2 Bilder im AD zu hinterlegen.
Diese werden in den Attributen

thumbnailPhoto
jpegPhoto

hinterlegt. Exchange ab 2007 bzw. Outlook verwendet ausschließlich das Bild welches unter thumbnailPhoto hinterlegt wird.
Wir verwenden deshalb in diesen Artikel auch ausschließlich dieses Attribut.

UserAccountPictures-003.png


Leider gibt es keine direkte Möglichkeit in der GUI diese Bilder zu bearbeiten - zu mindest ab Werk.
Unter Exchange gibt es entsprechende PowerShell CMDlets hierfür ... aber gerade hierbei bevorzuge ich doch die Optische Kontrolle.

Nachfolgend stelle ich 3 Möglichkeiten vor die mir sehr gut gefallen haben - und die Ihr beide parallel einsetzen könnt.



2.1 AD Photo Edit

Unter

http://www.cjwdev.co.uk/Software/ADPhotoEdit/Info.html

Könnt Ihr das Programm AD Photo Edit herunterladen.
Für erste Gehversuche reicht die Free Edition. Die kostenpflichtige Bulk Edition kann per Kommandozeile gesteuert werden und bietet sich zum Massenimport an.
In der Free Version könnt Ihr die Benutzer nur einzeln bearbeiten.
Ihr müsst die Anwendung als ein Domänen-Administrator starten!
Nach dem Start der Anwendung könnt Ihr unter Name den Benutzernamen des Benutzer angeben den Ihr bearbeiten wollt.
Lasst Ihr das Feld leer und klickt dann auf Search so zeigt er alle Benutzer an.

UserAccountPictures-004.png


Markiert links einen Benutzer und klickt dann rechts auf EditImage:

UserAccountPictures-005.png


UserAccountPictures-006.png




2.2 CodeTwo Active Photos

Das Tool ist Kostenlos auch bei einem Massenimport (im Gegensatz zum vorherigen) und kann auf der Webseite des Herstellers heruntergeladen werden:

http://www.codetwo.de/freeware/active-directory-photos/
http://www.codetwo.de/downloads/C2ADPhotosSetupEN.exe

Man kann damit komfortabel seine AD-Struktur durchforsten:

UserAccountPictures-008.png


Der Rest funktioniert ähnlich wie zuvor.


2.3 ADExt von Oli Dewdney

Oli Dewdney hat eine Erweiterung für die 'Active Directory-Benutzer und Computer geschrieben.
Leider ist seine Webseite nicht mehr erreichbar, deshalb bin ich mal so frei und biete den Download hier einmal an:

ADExt.zip


Die Installation ist auch als Textdatei in dem Archiv enthalten.
Kopiert die

adExt.dll

nach

C:\Windows\System32

auf einem Server / Computer auf dem auch die Active Directory Verwaltungstools installiert sind, typischerweise also z.B. einen Domänencontroller.
Startet danach eine Eingabeaufforderung und ruft folgenden Befehl auf:

C:\Windows\Microsoft.NET\Framework64\v2.0.50727\InstallUtil.exe C:\Windows\System32\adExt.dll


Wenn Ihr nun die Konsole Active Directory-Benutzer und Computer öffnet und einen Benutzer bearbeitet so habt Ihr einen weiteren Karteireiter Photo:

UserAccountPictures-007.png


Im Gegensatz zum AD Photo Edit rechnet der Bilder hierbei zwingend auf 96x96 Pixel herunter.



3 Windows 10

Das nächste Kapitel funktioniert unter Windows 7 / Server 2008 R2. Für Windows 10 habe ich das hier gefunden:

heineborn.com/tech/ad-user-pictures-in-windows-10

Eine eigene Umsetzung durch mein AutoIt Tool steht noch aus. Mache ich wenn ich es in einem Projekt brauche.


4 Foto auf Rechner und Servern bei der Anmeldung nutzen

So, die Bilder liegen also im Active Directory ... damit Windows diese aber bei der Anmeldung nutzt müssen diese im richtigen Format und Namen im Ordner

C:\ProgramData\Microsoft\User Account Pictures

hinterlegt werden ... einem Ordner auf den der Benutzer gar keine Schreibrechte hat.

Nun, die Lösung ist etwas bei der Anmeldung zu tun - per Script - welches das Bild ausliest und für den Benutzer setzt.

Nach etwas suchen fand ich mehrere Ansätze im Internet:

* PowerShell: http://www.reddit.com/r/sysadmin/comments/1dqv74/load_users_thumbnailphoto_attribute_to_windows/
* PowerShell: https://gallery.technet.microsoft.com/scriptcenter/Set-Windows-7-User-Tile-to-044f16d2

Die PowerShell Scripte haben wieder den Nachteil das diese einen Fehler auswerfen wenn die Powershell selbst nicht mit den richtigen Parametern gestartet werden.
Zudem muss die Ausführen nicht- oder selbstsignierter Scripte erlaubt werden usw. ... mag ich alles nicht

Dem Scripten konnte ich aber entnehmen das man eine DLL-Funktion aufrufen kann um das Bild für den Benutzer zu setzen.
Mit Regshot stellte ich fest dazu hierzu keinerlei Informationen in der Registry abgelegt werden - es wird nur eine

DOMAIN+USERNAME.dat

erstellt und abgelegt, wenn die Domäne ZNIL und der Anmeldename Bernhard ist also eine Datei

ZNIL+Bernhard.dat


Und dem Betriebssystem wird mitgeteilt das es die Daten hierzu einmal neu einlesen soll.
Dazu enthält die shell32.dll die Funktionen SetUserTile / ChangeUserTile.

Wie fast immer wollte ich mir etwas passendes in AutoIt nachprogrammieren - doch das hatte schon bereits jemand umgesetzt:

* AutoIt: https://www.autoitscript.com/forum/topic/127691-change-windows-profile-icon-tile/

Das ist allerdings ein sehr rudimentäres Beispiel ohne Fehlerbehandlung.
Wird es zum Beispiel von einem nicht-Domänenbenutzer aufgerufen oder passt sonst etwas nicht erscheint eine Warnfenster über einen Script-Fehler.
Aus gibt es sonst keinerlei Ausgaben über Erfolg oder Misserfolg etc.

Ich habe deshalb eine eigene Variante anhand des Beispiels erstellt:
Download: ADProfilePicture.zip

Das Tool kann einfach in ein Anmeldekript aufgenommen werden - oder einfach von Hand testen:

UserAccountPictures-009.png


Es sucht sich das AD-Objekt des aktuell angemeldeten Benutzers, extrahiert das Bild und speichert es im Benutzerprofil und setzt es als Benutzerbild lokal auf dem Rechner.
Die Änderungen werden unmittelbar übernommen - Ihr könnt also das Bild im Active Directory ändern und danach das Tool einfach noch mal starten.


5 Download

Download: ADProfilePicture.zip



6 Quellcode

Hier mein Quellcode dazu:

#NoTrayIcon
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Icon=Icon256-32.ico
#AutoIt3Wrapper_UseUpx=y
#AutoIt3Wrapper_Change2CUI=y
#AutoIt3Wrapper_Res_Comment=2015 Bernhard Linz
#AutoIt3Wrapper_Res_Fileversion=1.0.0.6
#AutoIt3Wrapper_Res_Fileversion_AutoIncrement=y
#AutoIt3Wrapper_Res_SaveSource=y
#AutoIt3Wrapper_Res_Language=1031
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <FileConstants.au3>
Opt('MustDeclareVars', 1)

; 2015 von Bernhard Linz für http://znil.net
; Bernhard@znil.de
; Bernhard.Linz@datagroup.de

; Holt sich aus dem Active Directory das dort hinterlegte Profilbild aus der Eigenschaft "thumbnailPhoto" und hinterlegt diese lokal auf dem Rechner
; unter C:\ProgramData\Microsoft\User Account Pictures bzw. setzt dieses so das es dort gespeichert wird.
; Dann wird im Startmenü und bei der Anmeldung eben dieses Bild gezeigt

; gefunden unter https://www.autoitscript.com/forum/topic/127691-change-windows-profile-icon-tile/
; ergänzt um eine Fehlerbehandlung / Fehlermeldungen und Statusmeldungen etc.

; #####################################################################################
; Vraibalen definieren
; $h_ = Handle / Zeiger
; $o_ = Objekt
; $s_ = String / Text
; $i_ = "Integer" = Zahl / Nummer
; $b_ = Boolean
; $a_ = Array

Global $o_MyError						; Zeiger auf die eigene Fehlerbehandlungsroutine
Global $h_thumbnailPhotoFile			; Handle auf Datei mit dem Profilbild
Global $s_thumbnailPhotoDATA			; Die Bildaten aus dem Active Directory
Global $o_ActiveDirectoryConnection		; Zeiger auf die Active Directory Verbindung
Global $s_DNSDomain						; DNS-Domänenname
Global $s_DomainController				; DNS-Hostname eines Domänencontrollers
Global $s_AD_Query						; Abfrageergebnis der Suche nach dem Benutzer im AD
Global $o_Command						; Objekt für Befehl gegen das Active Directory
Global $o_RootDSE						; Objekt für das Active Directory der Benutzerdomäne
Global $o_RecordSet						; Objekt für den Benutzereintrag im Active Directory
Global $o_LDAP							; Objekt für die eigentlichen Werte
Global $h_thumbnailPhotoDLLPath			; DLL Struktur mit dem Zeiger auf das Bild für DLL-Funktionsaufruf
Global $h_UserNameDLL					; DLL Struktur mit dem Zeiger auf den Benutzernamen für den DLL-Funktionsaufruf
Global $a_Return						; Array mit dem Ergebnis des DLL-Aufrufes
Global $s_Fileextension					; Daten könne als PNG oder JPEG hinterlegt sein

; #####################################################################################
; Funktionen
Func oMyError()
	ConsoleWrite(@ScriptName & " - Error Reading or Setting Profile Picture" & @CRLF)
EndFunc


; #####################################################################################
; Hauptprogramm

; Eigene Fehlerbehandlungsroutine setzen - greift bei Problemen und unterdrückt Fehlerdialoge
$o_MyError = ObjEvent("AutoIt.Error", "oMyError") ; Install a custom error handler

; Verbindung zum Active Directory herstellen
ConsoleWrite(@ScriptName & " - Connecting Active Directory ... ")
$o_ActiveDirectoryConnection = ObjCreate ( "ADODB.Connection" )
$o_ActiveDirectoryConnection.Provider = "ADsDSOObject"
$o_ActiveDirectoryConnection.Open ( "Active Directory Provider" )

; Set AD connection for command ... wofür auch immer das gebraucht wird
$o_Command = ObjCreate ( "ADODB.Command" )
If Not IsObj ( $o_Command ) Then
	ConsoleWrite(@ScriptName & " - Could not startup the Active Directory Provider" & @CRLF)
    Exit 1
EndIf
$o_Command.ActiveConnection = $o_ActiveDirectoryConnection
ConsoleWrite("connected!" & @CRLF)

; Daten aus AD ermitteln:
ConsoleWrite(@ScriptName & " - Query Active Directory for User " & @UserName & @CRLF)
$o_RootDSE = ObjGet ( "LDAP://RootDSE" )
If @Error Then
	ConsoleWrite("No Connection to Active Directory possible" & @CRLF)
    Exit
EndIf
$s_DNSDomain = $o_RootDSE.Get ( "defaultNamingContext" )  ; Retrieve the current AD domain name
$s_DomainController = $o_RootDSE.Get ( "dnsHostName" )
ConsoleWrite(@ScriptName & " - Domain Name       : " & $s_DNSDomain & @CRLF)
ConsoleWrite(@ScriptName & " - Domain Controller : " & $s_DomainController & @CRLF)
$s_AD_Query = "<LDAP://" & $s_DomainController & "/" & $s_DNSDomain & ">;(sAMAccountName=" & @UserName & ");distinguishedName;subtree"
$o_RecordSet = $o_ActiveDirectoryConnection.Execute ($s_AD_Query)
$o_LDAP = ObjGet ( "LDAP://" & $o_RecordSet.fields (0).value )
$s_thumbnailPhotoDATA = $o_LDAP.thumbnailPhoto
$o_ActiveDirectoryConnection.Close ( )

; Prüfen on denn Bilddaten vorliegen
If $s_thumbnailPhotoDATA = "" Then
	; Keine Bilddaten!
	ConsoleWrite(@ScriptName & " - User " & @UserName & " have no thumbnailPhoto stored in Active Directory!" & @CRLF)
    Exit 1
EndIf


; Kopie des Bildes im Benutzerprofil-Verzeichnis speichern
If StringInStr(BinaryToString($s_thumbnailPhotoDATA), "PNG") > 0 Then
	$s_Fileextension = ".png"
Else
	$s_Fileextension = ".jpg"
EndIf
ConsoleWrite(@ScriptName & " - save Copy of thumbnailPhoto in Userprofil (" & @UserProfileDir & "\thumbnailPhoto" & $s_Fileextension & ")" & @CRLF)
$h_thumbnailPhotoFile = FileOpen ( @UserProfileDir & "\thumbnailPhoto" & $s_Fileextension, $FO_OVERWRITE  + $FO_BINARY)
FileWrite ( $h_thumbnailPhotoFile, $s_thumbnailPhotoDATA )
FileClose ( $h_thumbnailPhotoFile )

; DLL-Routine aufrufen um das Bild für den Benutzer lokal auf dem Rechner/Server zu setzen:
ConsoleWrite(@ScriptName & " - activate thumbnailPhoto at local System ... ")
DLLCall("ole32.dll","int","CoInitialize","ptr",0)
$h_thumbnailPhotoDLLPath = DLLStructCreate("wchar[128]")
DllStructSetData($h_thumbnailPhotoDLLPath, 1, @UserProfileDir & "\thumbnailPhoto" & $s_Fileextension)
$h_UserNameDLL = DLLStructCreate("wchar[128]")
DllStructSetData($h_UserNameDLL, 1,  @LogonDomain & "\" & @UserName)
$a_Return = DllCall(@SystemDir & "\shell32.dll", "long", 262, "ptr", DllStructGetPtr($h_UserNameDLL), "int", 0, "ptr", DllStructGetPtr($h_thumbnailPhotoDLLPath))
ConsoleWrite("done!" & @CRLF)

Exit 0




7 Kommentare


nico.lehmann@berlin-partner.de

17 Monaten zuvor
Punktzahl 0++

Hi,

habe das Skript bei uns (AD, Win 8.1) getestet und musste leider feststellen, dass das Skript zwar funktioniert, wie erläutert, dies aber scheinbar nicht zur Anzeige des Profilbilds genügt. Im Datail:

- im AD per "Code2 Active Directory Photos" Bild hinterlegt - ADProfilePicture.exe ausgeführt - "thumbnailPhoto.jpg" wird unter %AppData% erzeugt - ".dat" wird unter "C:\ProgramData\Microsoft\User Account Pictures" erzeugt und enthält auch Daten - im Startmenü und am Anmelde-/Sperrbilschirm erscheint KEIN Bild

Ich habe die Bilder auch in diversen Größen eingefügt und auch die 96x96 Pixel-Variante funktionierte nicht. Fand den Ansatz eigentlich gut und interessant, da man hier eben nicht die Registry anpassen muss. Klappt aber leider - bei mir - nicht.

Anpassung des REG-Keys HKLM\Software\Microsoft\Windows\Current\Version\AccountPicture\Users und hinterlegen der fünf Bildgrößen im entsprechenden Profilpfad funktioniert hingegen.

Würde mich freuen, wenn ich einen Hinweis kriegen könnte, was ich falsch mache.

Ciao

Nico Lehmann

Markus

9 Monaten zuvor
Punktzahl 0++

Hallo,

funktioniert das Tool auch mit einem aktuellem Windows 10 ?

Dankeschön.

Viele Grüße

Markus

BLinz

9 Monaten zuvor
Punktzahl 0++
Tool ist unter W8 und W10 noch nicht getestet. Würde ich machen sobald ich es im Projekt brauche.

Stefan

7 Monaten zuvor
Punktzahl 0++

Das ist mal eine brauchbare Erklärung, was auch immer Tante M$ sich bei dem komplizierten Kram gedacht hat?!?

Aber auch ich würde mich sehr über ein Update freuen. Andere Varianten im Netz habe ich nicht gefunden...

Ich schaue auf jeden Fall wieder rein :-)

Thorsten

7 Monaten zuvor
Punktzahl 0++

Ich würde das Skript auch gerne unter Windows 10 einsetzen.

Über ein Update würde ich mich auch sehr freuen.
Kommentar hinzufügen
znilwiki freut sich über alle Kommentare. Sofern du nicht anonym bleiben möchtest, trage deinen Namen oder deine Email-Adresse ein oder melde dich an. Du kannst das Feld auch einfach leer lassen.