Ищите полный образец S.DS.AM со многими уже написанными расширениями AD - PullRequest
1 голос
/ 03 июля 2011

System.DirectoryServices.AccountManagement может быть расширен для поддержки дополнительных свойств для чтения и записи свойств AD.

Кто-нибудь знает о полном / полном примере реализации, который работает для AD, Exchange 2003 или 2010?

1 Ответ

2 голосов
/ 05 июля 2011

В Интернете нет ничего, о чем я знаю, но вы можете войти в мою коллекцию (которую я включил).

Одна вещь, которую вы, вероятно, заметите в моем коде, это то, что я почти полностью заменил стандартные операции get / set своим собственным кодом, который записывает непосредственно в базовый DirectoryEntry. Это связано с тем, что встроенная операция set не предназначена для обработки типов данных, которые являются массивами массивов (таких как атрибут jpegPhoto, который является массивом байтовых массивов, причем каждый байтовый массив представляет собой изображение).

Первый - это набор методов расширения, которые я использую для своих различных операций get / set.

    ''' <summary>
    ''' Checks if an attribute is available on the underlying object.
    ''' </summary>
    <Extension()> _
    Public Function IsAttributeDefined(ByVal prin As Principal, ByVal attribute As String) As Boolean
        'since some attributes may not exist in all schemas check to see if it exists first
        Dim uo As DirectoryEntry = DirectCast(prin.GetUnderlyingObject(), DirectoryEntry)

        'check for property, if it's not found return an empty array
        Return uo.Properties.Contains(attribute)
    End Function

#Region "Get Helpers"
    ''' <summary>
    ''' This function is the foundation for retrieving data
    ''' </summary>
    <Extension()> _
    Public Function ExtensionGetAttributeObject(ByVal prin As Principal, ByVal attribute As String) As Object()
        'check if the attribute exists on this object
        If IsAttributeDefined(prin, attribute) Then
            'if property exists then return the data
            Dim dirObj As DirectoryEntry = prin.GetUnderlyingObject()
            Dim val As Object() = (From c As Object In dirObj.Properties(attribute) Select c).ToArray()

            Return val
        Else
            'return an empty array if the attribute is not defined
            Return New Object(-1) {}
        End If
    End Function

    ''' <summary>
    ''' This is the primary function for retrieving attributes that contain only one value
    ''' </summary>
    <Extension()> _
    Public Function ExtensionGetSingleValue(ByVal prin As Principal, ByVal attribute As String) As Object
        'get the object
        Dim attributeValues() As Object = ExtensionGetAttributeObject(prin, attribute)

        'if the item length = 1 then return the first value, else don't
        If attributeValues.Length = 1 Then
            Return attributeValues(0)
        Else
            Return Nothing
        End If
    End Function

    ''' <summary>
    ''' Returns the string value of an attribute
    ''' </summary>
    ''' <remarks>(null if no value found)</remarks>
    <Extension()> _
    Public Function ExtensionGetSingleString(ByVal prin As Principal, ByVal attribute As String) As String
        Dim o As Object = ExtensionGetSingleValue(prin, attribute)
        If o IsNot Nothing Then
            Return o.ToString()
        Else
            Return String.Empty
        End If
    End Function

    ''' <summary>
    ''' Returns all of the strings contained in a multi-value attribute
    ''' </summary>
    <Extension()> _
    Public Function ExtensionGetMultipleString(ByVal prin As Principal, ByVal attribute As String) As String()
        'get the object array for this attribute
        Dim attributeValues() As Object = ExtensionGetAttributeObject(prin, attribute)

        'create a string array of the same length as the object array
        Dim array As String() = New String(attributeValues.Length - 1) {}

        'and copy over all items, converting them to strings as we go
        For i As Integer = 0 To attributeValues.Length - 1
            array(i) = attributeValues(i).ToString()
        Next

        'return the string array
        Return array
    End Function

    ''' <summary>
    ''' Returns the date value of an attribute 
    ''' </summary>
    ''' <remarks>(null if no value found)</remarks>
    <Extension()> _
    Public Function ExtensionGetSingleDate(ByVal prin As Principal, ByVal attribute As String) As String
        Dim o As Object = ExtensionGetSingleValue(prin, attribute)
        If o IsNot Nothing Then
            Dim dt As DateTime = Convert.ToDateTime(o)
            Return dt
        Else
            Return Nothing
        End If
    End Function

    ''' <summary>
    ''' Returns the principle represented by a column containing a single distinguished name
    ''' </summary>
    <Extension()> _
    Public Function ExtensionGetSingleDistinguishedName(ByVal prin As Principal, ByVal attribute As String) As Principal
        'get the distinguished name of the object as a string
        Dim dn As String = ExtensionGetSingleString(prin, attribute)

        'check for null
        If String.IsNullOrEmpty(dn) Then
            Return Nothing
        End If

        'get the principal represented by the DN
        Dim prinF As Principal = Principal.FindByIdentity(prin.Context, dn)

        'if it exists then prepare to return it
        If prinF IsNot Nothing Then
            'if the object is a userprincipal then get the user detailed principal for it.
            If TypeOf prinF Is UserPrincipal Then
                prinF = UserDetailedPrinciple.FindByIdentity(prin.Context, prinF.Name)
            End If

            'return the principal
            Return prinF
        End If

        'if all else fails return nothing
        Return Nothing
    End Function

    <Extension()> _
    Public Function ExtensionGetMultipleDistinguishedNames(ByVal prinParent As Principal, ByVal attribute As String) As Principal()
        'get the distinguished name of the object as a string
        Dim dn() As String = ExtensionGetMultipleString(prinParent, attribute)

        'array to hold list of principles
        Dim al As New List(Of Principal)()

        For Each d As String In dn
            'get the principal represented by the DN
            Dim prin As Principal = Principal.FindByIdentity(prinParent.Context, d)

            'if it exists then prepare to return it
            If prin IsNot Nothing Then
                'if the object is a userprincipal then get the user detailed principal for it.
                If TypeOf prin Is UserPrincipal Then
                    prin = UserDetailedPrinciple.FindByIdentity(prin.Context, prin.Name)
                ElseIf TypeOf prin Is GroupPrincipal Then
                    prin = GroupPrincipal.FindByIdentity(prin.Context, prin.Name)
                End If

                'return the principal
                al.Add(prin)
            End If
        Next

        'return list of principles
        Return al.ToArray()
    End Function

    ''' <summary>
    ''' Gets the bytes contained in an Octet String
    ''' </summary>
    <Extension()> _
    Public Function ExtentsionGetBytes(ByVal prin As Principal, ByVal attribute As String) As Byte()
        'get the data
        Dim o As Object = ExtensionGetSingleValue(prin, attribute)
        'check for nulls
        If o Is Nothing Then
            Return Nothing
        End If

        'get the byte array
        Dim byteArray() As Byte = DirectCast(o, Byte())

        'return the data
        Return byteArray
    End Function

    ''' <summary>
    ''' Gets the image contained in an Octet String type attribute
    ''' </summary>
    <Extension()> _
    Public Function ExtensionGetImage(ByVal prin As Principal, ByVal attribute As String) As Image
        'get bytes for attribute
        Dim bytearray() As Byte = ExtentsionGetBytes(prin, attribute)

        'if none returned return nothing
        If bytearray Is Nothing Then
            Return Nothing
        End If

        'read the bytes into a memory stream
        Dim ms As New MemoryStream(bytearray)

        'convert the memory stream to a bitmap and return it
        Return New Bitmap(ms)
    End Function

    <Extension()> _
    Public Function ExtensionGetImages(ByVal prin As Principal, ByVal attribute As String) As Image()
        'get all values in attribute
        Dim vals() As Object = ExtensionGetAttributeObject(prin, attribute)

        'array to hold images to be returned
        Dim al As New List(Of Image)()

        For Each o As Object In vals
            'get bytes
            Dim bytearray() As Byte = DirectCast(o, Byte())

            'if no data skip entry
            If bytearray Is Nothing Then
                Continue For
            End If

            'read the bytes into a memory stream
            Dim ms As New MemoryStream(bytearray)

            'convert the memory stream to a bitmap and add to the array
            al.Add(New Bitmap(ms))
        Next
        'return the list of images as an array.
        Return al.ToArray()
    End Function
#End Region

#Region "Set Helpers"
    Private Sub ExtensionSetDE(ByVal de As DirectoryEntry, ByVal attribute As String, ByVal value As Object)
        'check value, if it's null then don't add (null means clear only)
        If value IsNot Nothing Then
            de.Properties(attribute).Add(value)
        End If
    End Sub

    <Extension()> _
    Public Sub ExtensionSetValue(ByVal prin As Principal, ByVal attribute As String, ByVal value As Object)
        Dim uo As DirectoryEntry = prin.GetUnderlyingObject()
        uo.Properties(attribute).Clear()
        ExtensionSetDE(uo, attribute, value)
    End Sub

    <Extension()> _
    Public Sub ExtensionSetStringValue(ByVal prin As Principal, ByVal attribute As String, ByVal value As String)
        If String.IsNullOrEmpty(value) Then
            value = Nothing
        End If

        ExtensionSetValue(prin, attribute, value)
    End Sub

    <Extension()> _
    Public Sub ExtensionSetMultipleValueDirect(ByVal prin As Principal, ByVal attribute As String, ByVal values() As Object)
        'Normal ExtensionSet does not support saving array type values (octet string)
        ' so we set it directly on the underlying object
        Dim uo As DirectoryEntry = prin.GetUnderlyingObject()
        uo.Properties(attribute).Clear()

        If values IsNot Nothing Then
            For Each v As Object In values
                ExtensionSetDE(uo, attribute, v)
            Next
        End If
    End Sub

    <Extension()> _
    Public Sub ExtensionSetImage(ByVal prin As Principal, ByVal attribute As String, ByVal img As Image)
        'set data to attribute
        ExtensionSetValue(prin, attribute, img.SaveImageToByteArray())
    End Sub

    <Extension()> _
    Public Sub ExtensionSetImages(ByVal prin As Principal, ByVal attribute As String, ByVal img() As Image)
        'array list to hold the values temporarily
        Dim al As New ArrayList()

        'convert each image into a byte array
        For Each i As Image In img
            al.Add(i.SaveImageToByteArray())
        Next

        'set image array as value on attribute
        ExtensionSetMultipleValueDirect(prin, attribute, al.ToArray())
    End Sub

    <Extension()> _
    Public Function SaveImageToByteArray(ByVal img As Image) As Byte()
        'create a memory strea
        Dim ms As New MemoryStream()
        'write the image to the stream
        img.Save(ms, Imaging.ImageFormat.Jpeg)

        'save data to a byte array
        Dim bytes() As Byte = ms.ToArray()

        Return bytes
    End Function

    <Extension()> _
    Public Sub ExtensionSetMultipleDistinguishedNames(ByVal prin As Principal, ByVal attribute As String, ByVal dns() As Principal)
        'convert user principles into distinguished names
        Dim sc As New ArrayList()
        For Each u As UserDetailedPrinciple In dns
            sc.Add(u.DistinguishedName)
        Next

        ExtensionSetMultipleValueDirect(prin, attribute, sc.ToArray())
    End Sub

    ''' <summary>
    ''' Helps set the Thumbnail photo by resizing main photo and also saving original (possibly resized to 300xvariable)
    ''' to JpegPhoto.
    ''' </summary>
    ''' <param name="imgO">The iamge to use as the users thumbnail photo</param>
    ''' <remarks>You still NEED to call .Save() after calling this sub
    ''' as this sub does not call save().
    ''' </remarks>
    <Extension()> _
    Public Sub SetUserPhoto(ByVal prin As Principal, ByVal imgO As Image)
        'resize the image for thumbnail
        Dim imgN As Bitmap = ResizeImage(imgO, 100)

        'check if we need to resize for medium sized image (300px high max
        Dim imgM As Bitmap
        If imgO.Height > 300 Then
            imgM = ResizeImage(imgO, 300)
        Else
            imgM = imgO
        End If

        'save small image to the users profile
        ExtensionSetImage(prin, "thumbnailPhoto", imgN)
        'save original to the jpegPhoto attribute
        ExtensionSetImages(prin, "jpegPhoto", New Image() {imgM})
    End Sub

    Private Function ResizeImage(ByVal imgO As Bitmap, ByVal Height As Integer) As Bitmap
        'if the image is smaller/equal to the requested height return original
        If imgO.Height <= Height Then
            Return imgO
        End If

        'images are fixedHeightxVariable, so we need to calculate the variable portion
        Dim width As Integer = (Convert.ToDecimal(imgO.Width) / Convert.ToDecimal(imgO.Height)) * Height

        'resize the image
        Dim imgN As New Bitmap(width, Height)
        Dim g As Graphics = Graphics.FromImage(imgN)
        g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
        g.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic

        'draw in resized form
        g.DrawImage(imgO, 0, 0, width, Height)

        'return resized image
        Return imgN
    End Function

    <Extension()> _
    Public Function Rename(ByVal prin As Principal, ByVal NewName As String) As Principal
        'escape commas
        NewName = NewName.Replace(",", "\,")

        'get directory object for move
        Dim de As DirectoryEntry = prin.GetUnderlyingObject()

        'move
        de.Rename(String.Format("CN={0}", NewName))
        de.CommitChanges()

        'get the new object by name and return it
        Return New ADConnection(prin.Context).GetPrincipalByName(prin.Guid.ToString())
    End Function
#End Region

Вот код в действии в моем пользовательском принципе:

<DirectoryObjectClass("user")> _
<DirectoryRdnPrefix("CN")> _
Public Class UserDetailedPrinciple
    Inherits UserPrincipal

    <DirectoryProperty("initials")> _
    Public Property MiddleInitial() As String
        Get
            Return ExtensionGetSingleString("initials")
        End Get
        Set(ByVal value As String)
            ExtensionSetStringValue("initials", value)
        End Set
    End Property

    <DirectoryProperty("wWWHomePage")> _
    Public Property HomePage() As String
        Get
            Return ExtensionGetSingleString("wWWHomePage")
        End Get
        Set(ByVal value As String)
            ExtensionSetStringValue("wWWHomePage", value)
        End Set
    End Property

    <DirectoryProperty("url")> _
    Public Property URLs() As String()
        Get
            Return ExtensionGetMultipleString("url")
        End Get
        Set(ByVal value As String())
            ExtensionSetMultipleValueDirect("url", value)
        End Set
    End Property

    <DirectoryProperty("info")> _
    Public Property Notes() As String
        Get
            Return ExtensionGetSingleString("info")
        End Get
        Set(ByVal value As String)
            ExtensionSetStringValue("info", value)
        End Set
    End Property

    Public ReadOnly Property ObjectType() As String
        Get
            Dim types() As String = ExtensionGetMultipleString("objectClass")
            Return types.Last()
        End Get
    End Property

    <DirectoryProperty("thumbnailPhoto")> _
    Public Property ThumbnailPhoto() As Image
        Get
            Return ExtensionGetImage("thumbnailPhoto")
        End Get
        Set(ByVal value As Image)
            ExtensionSetImage("thumbnailPhoto", value)
        End Set
    End Property

    <DirectoryProperty("thumbnailLogo")> _
    Public Property ThumbnailLogo() As Image
        Get
            Return ExtensionGetImage("thumbnailLogo")
        End Get
        Set(ByVal value As Image)
            ExtensionSetImage("thumbnailLogo", value)
        End Set
    End Property

    <DirectoryProperty("jpegPhoto")> _
    Public Property JpegPhoto() As Image()
        Get
            Return ExtensionGetImages("jpegPhoto")
        End Get
        Set(ByVal value As Image())
            ExtensionSetImages("jpegPhoto", value)
        End Set
    End Property

    <DirectoryProperty("title")> _
    Public Property Title() As String
        Get
            Return ExtensionGetSingleString("title")
        End Get
        Set(ByVal value As String)
            ExtensionSetStringValue("title", value)
        End Set
    End Property

    <DirectoryProperty("department")> _
    Public Property Department() As String
        Get
            Return ExtensionGetSingleString("department")
        End Get
        Set(ByVal value As String)
            ExtensionSetStringValue("department", value)
        End Set
    End Property

    <DirectoryProperty("company")> _
    Public Property Company() As String
        Get
            Return ExtensionGetSingleString("company")
        End Get
        Set(ByVal value As String)
            ExtensionSetStringValue("company", value)
        End Set
    End Property

    <DirectoryProperty("manager")> _
    Public Property Manager() As UserDetailedPrinciple
        Get
            Dim mgr As UserDetailedPrinciple = ExtensionGetSingleDistinguishedName("manager")

            If mgr IsNot Nothing Then
                If Me.Guid <> mgr.Guid Then
                    Return mgr
                End If
            End If

            Return Nothing
        End Get
        Set(ByVal value As UserDetailedPrinciple)
            'check for nulls
            If value Is Nothing Then
                ExtensionSetStringValue("manager", Nothing)
            Else
                ExtensionSetStringValue("manager", value.DistinguishedName)
            End If
        End Set
    End Property

    <DirectoryProperty("assistant")> _
    Public Property Assistant() As UserDetailedPrinciple
        Get
            Dim assist As UserDetailedPrinciple = ExtensionGetSingleDistinguishedName("assistant")

            If assist IsNot Nothing Then
                Return assist
            End If

            Return Nothing
        End Get
        Set(ByVal value As UserDetailedPrinciple)
            'check for nulls
            If value Is Nothing Then
                ExtensionSetStringValue("assistant", Nothing)
            Else
                ExtensionSetStringValue("assistant", value.DistinguishedName)
            End If
        End Set
    End Property

    <DirectoryProperty("directReports")> _
    Public Property DirectReports() As Principal()
        Get
            Dim dReports As Principal() = ExtensionGetMultipleDistinguishedNames("directReports")
            Return dReports
        End Get
        Set(ByVal value As Principal())
            ExtensionSetMultipleDistinguishedNames("directReports", value)
        End Set
    End Property

    <DirectoryProperty("homePhone")> _
     Public Property HomePhone() As String
        Get
            Return ExtensionGetSingleString("homePhone")
        End Get
        Set(ByVal value As String)
            ExtensionSetStringValue("homePhone", value)
        End Set
    End Property

    <DirectoryProperty("pager")> _
     Public Property Pager() As String
        Get
            Return ExtensionGetSingleString("pager")
        End Get
        Set(ByVal value As String)
            ExtensionSetStringValue("pager", value)
        End Set
    End Property

    <DirectoryProperty("otherTelephone")> _
    Public Property OtherTelephone() As String()
        Get
            Return ExtensionGetMultipleString("otherTelephone")
        End Get
        Set(ByVal value As String())
            ExtensionSetMultipleValueDirect("otherTelephone", value)
        End Set
    End Property

    <DirectoryProperty("physicalDeliveryOfficeName")> _
    Public Property PhysicalLocation() As String
        Get
            Return ExtensionGetSingleString("physicalDeliveryOfficeName")
        End Get
        Set(ByVal value As String)
            ExtensionSetStringValue("physicalDeliveryOfficeName", value)
        End Set
    End Property

    <DirectoryProperty("l")> _
    Public Property AddressCity() As String
        Get
            Return ExtensionGetSingleString("l")
        End Get
        Set(ByVal value As String)
            ExtensionSetStringValue("l", value)
        End Set
    End Property

    <DirectoryProperty("postOfficeBox")> _
    Public Property AddressPOBox() As String
        Get
            Return ExtensionGetSingleString("postOfficeBox")
        End Get
        Set(ByVal value As String)
            ExtensionSetStringValue("postOfficeBox", value)
        End Set
    End Property

    <DirectoryProperty("st")> _
    Public Property AddressState() As String
        Get
            Return ExtensionGetSingleString("st")
        End Get
        Set(ByVal value As String)
            ExtensionSetStringValue("st", value)
        End Set
    End Property

    <DirectoryProperty("streetAddress")> _
    Public Property Address() As String
        Get
            Return ExtensionGetSingleString("streetAddress")
        End Get
        Set(ByVal value As String)
            ExtensionSetStringValue("streetAddress", value)
        End Set
    End Property

    <DirectoryProperty("postalCode")> _
    Public Property AddressZipCode() As String
        Get
            Return ExtensionGetSingleString("postalCode")
        End Get
        Set(ByVal value As String)
            ExtensionSetStringValue("postalCode", value)
        End Set
    End Property

    <DirectoryProperty("c")> _
     Public Property AddressCountry() As String
        Get
            Return ExtensionGetSingleString("c")
        End Get
        Set(ByVal value As String)
            ExtensionSetStringValue("c", value)
        End Set
    End Property

    <DirectoryProperty("whenCreated")> _
    Public ReadOnly Property Created() As Nullable(Of DateTime)
        Get
            Return ExtensionGetSingleDate("whenCreated")
        End Get
    End Property

    <DirectoryProperty("whenChanged")> _
    Public ReadOnly Property LastModified() As Nullable(Of DateTime)
        Get
            Return ExtensionGetSingleDate("whenChanged")
        End Get
    End Property

    Public Sub New()
        MyBase.New(ADConnection.CurrentADPrincipalContext)
    End Sub
    Public Sub New(ByVal context As PrincipalContext)
        MyBase.New(context)

    End Sub

    Public Overloads Shared Function FindByIdentity(ByVal context As PrincipalContext, ByVal identityValue As String) As UserDetailedPrinciple
        Return DirectCast(Principal.FindByIdentityWithType(context, GetType(UserDetailedPrinciple), identityValue), UserDetailedPrinciple)
    End Function

    Public Overloads Shared Function FindByIdentity(ByVal context As PrincipalContext, ByVal identityType As IdentityType, ByVal identityValue As String) As UserDetailedPrinciple
        Return DirectCast(Principal.FindByIdentityWithType(context, GetType(UserDetailedPrinciple), identityType, identityValue), UserDetailedPrinciple)
    End Function
End Class
...