Problem creating distribution lists on exchange server 2010 via power shell

Hi there,

we have an it management system running where we can put users into special groups. Eg. every user who uses Microsoft Word is in that group. Furthermore this tool has a kind of task server that can run tasks periodically.

The idea now is, that we would like to create distribution lists on the exchange server with the mentioned groups, like "All Word Users".

The task servers has some requirements that cannot easily be changed:

* The TaskServer can run multiple tasks threaded simultaneously
* The TaskServer is a windows service that runs under a domain account with local admin rights.
* The TaskServer-User has no authorization to do anything on the exchange server
* It is possible to impersonate a task to run with appropriate rights.

That's the prehistory so far. The solution looks as follows:

* I have created this task.
* I have installed the exchange power shell commandlets
* I have created a power shell command with runspace and pipeline
* I have impersonated the command with appropriate rights

The mean thing is now, that my code functions properly when

* I run the code without any service involved in a console application.
* It also runs as a windows service hosted in a console application.
* It does not run, when the service is hosted in a windows service (installutil etc.). I get the following error message:

Das Windows PowerShell-Snap-In Microsoft.Exchange.Management.PowerShell.E2010 kann aufgrund des folgenden Fehlers nicht geladen werden: Der Typeninitialisierer für "Microsoft.Exchange.Data.Directory.Globals" hat eine Ausnahme verursacht.
   bei System.Management.Automation.Runspaces.RunspaceConfigForSingleShell.LoadCustomPSSnapIn(PSSnapInInfo mshsnapinInfo)
   bei System.Management.Automation.Runspaces.RunspaceConfigForSingleShell.LoadPSSnapIn(PSSnapInInfo mshsnapinInfo)
   bei System.Management.Automation.Runspaces.RunspaceConfigForSingleShell.LoadPSSnapIn(PSSnapInInfo mshsnapinInfo, PSSnapInException& warning)
   bei System.Management.Automation.Runspaces.RunspaceConfigForSingleShell.DoAddPSSnapIn(String name, PSSnapInException& warning)
   bei System.Management.Automation.Runspaces.RunspaceConfiguration.AddPSSnapIn(String name, PSSnapInException& warning)
   bei mpc.Utilities.PowerShellCommand.AddSnapIn(String psSnapInName) in E:\Visual Studio

--> Short Translation: "The Windows PowerShell-SnapIn Microsoft.Exchange.... could not be loaded due to an error. The Type Initialization "Microsoft.Exchange.Data.Directory.Globals" has thrown an excetion at ...."

I have already checked a possible x86/x64 issue. Both the service as well as the task are compiled with "Any CPU".

Any idea would be more then welcomed.


Here is my sourcecode:

 Private Sub CreateExchangeDistributionList(ByVal name As String, ByVal organizationalUnit As String, ByVal samAccountName As String)

            '            ModuleLibrarySharedConfig.GetConfigValue(BindableConfiguration.StandardParameterNamesEnum.ImpersonationUserDomain),
            '            ModuleLibrarySharedConfig.GetConfigValue(BindableConfiguration.StandardParameterNamesEnum.ImpersonationUserPassword))

            Dim cmd As String = String.Format("New-DistributionGroup -Name ""{0}"" -OrganizationalUnit ""{1}"" -SamAccountName ""{2}"" -Type ""Distribution""",
            Dim ps As New PowerShellCommand


            If ps.HasError Then
                Throw New Exception(ps.GetLog)
            End If

        End Sub

Public Class PowerShellCommand

        ' //// EVENTS

        ' //// DEKLARATIONEN

        Private _log As String
        Private _hasErrors As Boolean

        Private ReadOnly _runspace As Runspace
        Private ReadOnly _pipeline As Pipeline

        ' //// PROPERTIES
        Public ReadOnly Property HasError As Boolean
                Return _hasErrors
            End Get
        End Property
        Public ReadOnly Property GetLog As String
                Return _log
            End Get
        End Property

        ' //// EVENTHANDLER

        ' //// METHODEN

        Public Sub AddSnapIn(ByVal psSnapInName As String)

            ' Exchange Snapin
            ' "Microsoft.Exchange.Management.PowerShell.E2010"

            Dim snapInWarning As New PSSnapInException
            Dim snapInInfo = _runspace.RunspaceConfiguration.AddPSSnapIn(psSnapInName, snapInWarning)
            snapInInfo.LogPipelineExecutionDetails = True

            If snapInWarning IsNot Nothing Then
                Throw New Exception("Power Shell SnapIn Warning", snapInWarning)
            End If

        End Sub
        Public Sub AddCommand(ByVal commandText As String)

            ' "New-DistributionGroup -Name ""Mail_Abwesenheitsplaner_U"" -OrganizationalUnit """" -SamAccountName ""Mail_Abwesenheitsplaner_U"" -Type ""Distribution"""
            _pipeline.Commands.Add(New Command(commandText, True))

        End Sub

        ' //// INIT

        Public Sub New()
            Dim runspaceConfig = RunspaceConfiguration.Create()
            _runspace = RunspaceFactory.CreateRunspace(runspaceConfig)
            _pipeline = _runspace.CreatePipeline

        End Sub

        ' //// ENUMS

        ' //// INLINE KLASSEN

        Public Sub Run()



                AddLogEntry("PowerShell - Execution started at " & Now.ToString)
                AddLogEntry("Current User: " & System.Environment.UserName)


                Dim out = _pipeline.Invoke()
                Dim builder As New System.Text.StringBuilder

                Dim info = _pipeline.PipelineStateInfo
                If (info.State <> PipelineState.Completed) Then
                    AddLogEntry("---PipelineState: " & info.State.ToString)
                End If

                If _pipeline.Error.Count > 0 Then
                End If

            Catch ex As Exception


            End Try

            If _hasErrors Then
            End If

        End Sub

        Private Sub ClearLog()
            _log = ""
            _hasErrors = False
        End Sub

        Private Sub AddLogEntry(ByVal entry As String)
            _log &= entry & Environment.NewLine
        End Sub

        Private Sub LogError(ByVal pipelineError As PipelineReader(Of Object))

            Dim x As Integer
            Dim log As New System.Text.StringBuilder

            If pipelineError.Count > 0 Then

                While Not pipelineError.EndOfPipeline
                    log.AppendFormat("---- Error from pipeline [{0}]", x)
                    Dim value = TryCast(pipelineError.Read(), PSObject)
                    If value IsNot Nothing Then
                        'get the ErrorRecord
                        Dim r = TryCast(value.BaseObject, ErrorRecord)
                        If r IsNot Nothing Then
                            'build whatever kind of message your want
                            log.AppendLine(Convert.ToString(r.InvocationInfo.MyCommand.Name) & " : " & Convert.ToString(r.Exception.Message))
                            log.AppendLine(String.Format("+ CategoryInfo: {0}", r.CategoryInfo))
                            log.AppendLine(String.Format("+ FullyQualifiedErrorId: {0}", r.FullyQualifiedErrorId))
                        End If
                    End If
                End While
            End If


        End Sub
        Private Sub LogError(ByVal ex As Exception)


            If ex.InnerException IsNot Nothing Then
            End If

        End Sub
        Private Sub LogError(ByVal err As String)

            _hasErrors = True

        End Sub

        Public Shared Sub FlushLogToEventLog(ByVal log As String)

            Dim sSource As String
            Dim sLog As String
            Dim sEvent As String
            Dim sMachine As String

            sSource = "PowerShell Log"
            sLog = "Application"
            sEvent = log
            sMachine = "."

            If Not EventLog.SourceExists(sSource, sMachine) Then
                EventLog.CreateEventSource(sSource, sLog, sMachine)
            End If

            Dim eLog As New EventLog(sLog, sMachine, sSource)
            eLog.WriteEntry(sEvent, EventLogEntryType.Error, 234, CType(3, Short))

        End Sub

    End Class

Open in new window

Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Neil RussellTechnical Development LeadCommented:
Your code for StartImpersonation(...) is all commented out. Is that just a typo in your posting??
srexpAuthor Commented:
That's a typo in my posting. This should not be commented out. The error occurs with impersonation to.

And as I said. The TaskServer User does not have rights to create lists on the exchange server. The code that gets executed in the three metioned scenarios is the same. Tow are working one not.

Here is the code I'm using for the impersonation:

Private Sub ImpersonateValidUser(ByVal userName As String, ByVal domain As String, ByVal password As String)
            ImpersonateValidUser(userName, domain, password, LOGON32_LOGON_INTERACTIVE)
        End Sub
        Private Sub ImpersonateValidUser(ByVal userName As String, ByVal domain As String, ByVal password As String, ByVal provider As Integer)
            Dim tempWindowsIdentity As WindowsIdentity = Nothing
            Dim token As IntPtr = IntPtr.Zero
            Dim tokenDuplicate As IntPtr = IntPtr.Zero

                If RevertToSelf() Then
                    If LogonUser(userName, domain, password, provider, LOGON32_PROVIDER_DEFAULT, token) <> 0 Then
                        If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then
                            tempWindowsIdentity = New WindowsIdentity(tokenDuplicate)
                            impersonationContext = tempWindowsIdentity.Impersonate()
                            Throw New Win32Exception(Marshal.GetLastWin32Error())
                        End If
                        Throw New Win32Exception(Marshal.GetLastWin32Error())
                    End If
                    Throw New Win32Exception(Marshal.GetLastWin32Error())
                End If
                If token <> IntPtr.Zero Then
                End If
                If tokenDuplicate <> IntPtr.Zero Then
                End If
            End Try
        End Sub

Open in new window

srexpAuthor Commented:
I am using Remote Power Shell now to avoid this problem.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
srexpAuthor Commented:
Not solved. Workaround does work.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.