none
Is it possible to programmatically change a folder's properties in Exch2010 SP1? RRS feed

  • Question

  • I've gotten my script sorted out to create a folder in everyone's mailbox (powershell) now I need to change that folders properties.  Specifically, set a Home Page and select "show that home page by default".  I've come across a few methods however they are either for 2003 or utilize functions of 2007 that I believe are no longer available in 2010 (WebDAV is discontinued right?)

    http://social.technet.microsoft.com/Forums/en/exchangesvrdevelopment/thread/d4516dca-34bb-4a9c-83df-f2b3df94cfc4

    I played around with that for a few days (converted to vb) and couldn't come up with anything that would work in my environment.  It doesn't need to be powershell, at this point I would take anything.  Just need to fire it off after the folder is created.

    I would appreciate any insight!

    Wednesday, October 5, 2011 4:28 PM

Answers

All replies

  • Hi JEmlay,

    yes, WebDAV is gone. But the example Glen post in that folder uses EWS, which is available. Glen used the EWS Managed API 1.0 in that script. The object model has slightly changed since then.

    I've posted an updated version of that article on my blog:
    http://www.infinitec.de/post/2011/10/05/Setting-the-Homepage-of-an-Exchange-folder-using-the-EWS-Managed-API.aspx

    Kind regards,
    Henning

    • Marked as answer by JEmlay Thursday, October 6, 2011 3:43 PM
    Wednesday, October 5, 2011 5:33 PM
  • Thanks for your reply!

    EDIT:

    Scratch all that.  So I finally got my folder addition PS code added to your C# script and fixed your function call.  Move "service" to the end and put quotes around your URL.  Since I know squat about C# that was quit a task for me!  From the working C# code I converted as much of it to VB as I could.  I'm having an issue with the string conversion to HEX.

     

        Private Function ConvertToHex(ByVal input As String) As String
            Return String.Join(String.Empty, input.[Select](Function(c) CInt(c).ToString("x2") & "00").ToArray())
        End Function

     

    I can't get this to work at all.  I've tried various ways of converting a string to hex all I wind up with is chineese looking characters in the URL property box.

     

    Error    1    Overload resolution failed because no accessible 'Select' can be called with these arguments:
        Extension method 'Public Function Select(Of TResult)(selector As System.Func(Of Char, Integer, TResult)) As System.Collections.Generic.IEnumerable(Of TResult)' defined in 'System.Linq.Enumerable': Nested function does not have a signature that is compatible with delegate 'System.Func(Of Char, Integer, TResult)'.
        Extension method 'Public Function Select(Of TResult)(selector As System.Func(Of Char, Integer, TResult)) As System.Collections.Generic.IEnumerable(Of TResult)' defined in 'System.Linq.Enumerable': Data type(s) of the type parameter(s) cannot be inferred from these arguments. Specifying the data type(s) explicitly might correct this error.
        Extension method 'Public Function Select(Of TResult)(selector As System.Func(Of Char, TResult)) As System.Collections.Generic.IEnumerable(Of TResult)' defined in 'System.Linq.Enumerable': 'Char' values cannot be converted to 'Integer'. Use 'Microsoft.VisualBasic.AscW' to interpret a character as a Unicode value or 'Microsoft.VisualBasic.Val' to interpret it as a digit.
        Extension method 'Public Function Select(Of TResult)(selector As System.Func(Of Char, TResult)) As System.Collections.Generic.IEnumerable(Of TResult)' defined in 'System.Linq.Enumerable': Data type(s) of the type parameter(s) cannot be inferred from these arguments. Specifying the data type(s) explicitly might correct this error.    c:\test\ConsoleApplication1\Module1.vb    65    42    ConsoleApplication1

     

    On a side note, I figured out my problem with Glen's existing code.  VS 2010 with framework 4 automatically chooses framework 4 CLIENT.  This mixed with the EWS DLL do not play nice together.  You run the code and it blows out the DLL reference due to microsoft.web dependency.  After setting it to straight framework 4 that fixed that mess.

    • Edited by JEmlay Thursday, October 6, 2011 1:55 AM
    Wednesday, October 5, 2011 11:48 PM
  • Hi,

    here is the ConvertToHex method in VB:

    Private Function ConvertToHex(input As String) As String
         Return String.Join(String.Empty, input.Select(Function(c)
    AscW(c).ToString("x2") + "00").ToArray())
    End Function

    Kind regards,
    Henning

    Thursday, October 6, 2011 2:43 PM
  • Again, thank you very much.  That should wrap this up.  Now I'm adding the folder and setting the properties from an console app of which I pass the email address from PS and do my folder checking on both ends.

    When I'm done with everything I'll post back with the entire solution in case anyone else stumbles upon it.

    Thursday, October 6, 2011 3:43 PM
  • Here's the VB.NET CONSOLE version that will also add the folder as well as set the properties.  Just run the EXE like so:

    programname.exe user@domain.com

    I still use powershell to get-mailbox and feed the EXE each email address IF the folder does not exist.  I run this daily so it picks up new users.  Set it and forget it!  This works great for those people that use postini so they can set a folder that goes straight to their spam.  However in OL 2010 you have to store your password in IE then go into OL and it'll be set.  It would seem MS secured cookie creation in OL2010???

     

    Imports Microsoft.Exchange.WebServices.Data
    Imports System.IO
    Imports System.Globalization
    Imports System.Net
    Imports System.Text.RegularExpressions

    Module Module1

        Sub Main()

            Try

                If My.Application.CommandLineArgs.Count = 1 Then

                    If CheckEmail(My.Application.CommandLineArgs(0)) = True Then

                        Dim NewFolderName As String = "FOLDERNAME"

                        Dim service As New ExchangeService(ExchangeVersion.Exchange2010_SP1)
                        service.Url = New Uri("https://domain.com/EWS/Exchange.asmx")
                        ' Set this to run as account that can impersonate each user.  Or comment it out and run the app while logged in as that user.  For example, only run while logged in as administrator.
                        ' service.Credentials = New NetworkCredential("USERNAME", "PASSWORD", "DOMAIN")
                        ' Comment this out if you do not want to use impersonation and the above specified account has access to all mailboxes.
                        service.ImpersonatedUserId = New ImpersonatedUserId(ConnectingIdType.SmtpAddress, My.Application.CommandLineArgs(0))

                        Dim fvFolderView As New Microsoft.Exchange.WebServices.Data.FolderView(1)
                        Dim SfSearchFilter As New Microsoft.Exchange.WebServices.Data.SearchFilter.IsEqualTo([Microsoft].Exchange.WebServices.Data.FolderSchema.DisplayName, NewFolderName)
                        Dim findFolderResults = service.FindFolders([WellKnownFolderName].MsgFolderRoot, SfSearchFilter, fvFolderView)


                        If findFolderResults.TotalCount = 0 Then
                            Console.WriteLine("Not Found")
                            Dim newFolder As New Folder(service)
                            newFolder.DisplayName = NewFolderName
                            newFolder.Save(WellKnownFolderName.MsgFolderRoot)
                            Console.WriteLine("Created")
                        Else
                            Console.WriteLine("Folder Already Exists")
                        End If

                        SetFolderHomePage({"FOLDERNAME"}, "http://URL.COM", service)

                    Else
                        Console.WriteLine("You Must Specify Only One Argument, An Email Address")
                    End If

                Else
                    Console.WriteLine("You Must Specify Only One Argument, An Email Address")
                End If


            Catch ex As Exception
                Console.WriteLine("Something Bad Happened, Usually Bad Permissions")
            End Try

        End Sub

        Private Sub SetFolderHomePage(ByVal pathFragments As IEnumerable(Of String), ByVal url As String, ByVal service As ExchangeService)

            Dim folderWebviewinfoProperty = New ExtendedPropertyDefinition(14047, MapiPropertyType.Binary)
            Dim root = Folder.Bind(service, WellKnownFolderName.MsgFolderRoot)
            Dim targetFolder = root

            For Each fragment In pathFragments
                Dim result = service.FindFolders(targetFolder.Id, New SearchFilter.IsEqualTo(FolderSchema.DisplayName, fragment), New FolderView(1))
                If result.TotalCount = 0 Then
                    Throw New InvalidOperationException(String.Format("Folder fragment {0} was not found.", fragment))
                End If
                targetFolder = result.Folders(0)
            Next

            targetFolder.SetExtendedProperty(folderWebviewinfoProperty, EncodeUrl(url))
            targetFolder.Update()

        End Sub

        Public Function CheckEmail(ByVal EMAIL As String) As Boolean

            Try
                Dim pattern As String
                pattern = "^([0-9a-zA-Z]([-\.\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$"

                If Regex.IsMatch(EMAIL, pattern) Then
                    Return True
                Else
                    Console.WriteLine("Malformed Email Address")
                    End
                End If
            Catch ex As Exception
                Console.WriteLine("Something went wrong with email address verification")
                End
            End Try

        End Function

        Private Function EncodeUrl(ByVal url As String) As Byte()
            Dim writer = New StringWriter()

            Dim dataSize = ((ConvertToHex(url).Length \ 2) + 2).ToString("X2")

            writer.Write("02")
            ' Version
            writer.Write("00000001")
            ' Type
            writer.Write("00000001")
            ' Flags
            writer.Write("00000000000000000000000000000000000000000000000000000000")
            ' unused
            writer.Write("000000")
            writer.Write(dataSize)
            writer.Write("000000")
            writer.Write(ConvertToHex(url))
            writer.Write("0000")

            Dim buffer = HexStringToByteArray(writer.ToString())
            Return buffer

        End Function

        Private Function ConvertToHex(ByVal input As String) As String
            Return String.Join(String.Empty, input.Select(Function(c) AscW(c).ToString("x2") + "00").ToArray())
        End Function

        Private Function HexStringToByteArray(ByVal input As String) As Byte()
            Return Enumerable.Range(0, input.Length \ 2).[Select](Function(index) Byte.Parse(input.Substring(index * 2, 2), NumberStyles.AllowHexSpecifier)).ToArray()
        End Function

    End Module

    • Edited by JEmlay Thursday, October 6, 2011 10:54 PM
    Thursday, October 6, 2011 10:50 PM