none
problem with EWS script to delete inbox rules in peoples mailbox using multi threading RRS feed

  • Question


  • Hi there 

    I am trying to write a script to remove 2 inbox rules from multiple peoples mailbox ('Redirect1' and 'DL Redirect')

    but its not working not sure what is wrong with it - it doesnt delete the rule and doesnt seem to move through the list of people when it did work for 1 person - not using multithreading - reason i want to use this is there are over 2000 people with the rules in their inbox

    [CmdletBinding()]

        param(



        [parameter( Mandatory=$false, Position=0)]
    [switch]$MultiThread=$false



    )



    begin{




            $Jobs = @()
            $Sessionstate = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
            $RunspacePool = [RunspaceFactory]::CreateRunspacePool(1, 10,$Sessionstate, $Host)
            $RunspacePool.ApartmentState = "STA"
            $RunspacePool.Open()


            $error.clear()
            [string]$LogFile = "C:\Temp\Log.txt"  
            if($LogFile)
            {
                Remove-Item $LogFile -ea SilentlyContinue
            }


            $proxysettings = New-PSSessionOption -ProxyAccessType IEConfig

            Import-Module -Name "C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll"
            $psCred = Get-Credential #get admin creds
            $cred = New-Object System.Net.NetworkCredential($psCred.UserName.ToString(),$psCred.GetNetworkCredential().password.ToString())
            $Exchangeservice = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService
            $ExchangeService.credentials = $cred
            $PrimarySmtpAddress = Import-Csv .\testrule.csv


    }



    process {

      function Get-CreateRule()
      {
           param(


             [Parameter(ValueFromPipelineByPropertyName=$true)]
              [string]
                $alias,  
            [Microsoft.Exchange.WebServices.Data.ExchangeService]$exchangeService


           )  



        write-host -ForegroundColor DarkBlue "DEF in function"
        write-host -ForegroundColor DarkGreen $alias


            $rules = $ExchangeService.GetInboxRules($alias)
            Write-Host -ForegroundColor DarkGreen $rules
          foreach($rule in $rules)
            {
                Write-Host -ForegroundColor DarkGreen $rule.displayname
                if($rule.displayname -eq 'Redirect1')
                {

                    $delrule = $rule.Id
                    $RuleOperation = [Microsoft.Exchange.WebServices.Data.DeleteRuleOperation]::new($delrule)


                }
                if($rule.displayname -eq 'DL Redirect1')
                {

                    $delrule1 = $rule.Id
                    $RuleOperation = [Microsoft.Exchange.WebServices.Data.DeleteRuleOperation]::new($delrule1)


                }

                $ExchangeService.UpdateInboxRules([Microsoft.Exchange.WebServices.Data.RuleOperation[]]@($RuleOperation), $true)




    }


      # $rules     

      }

        if($MultiThread)
        {


            $ScriptBlock = [scriptblock]::Create((Get-ChildItem Function:\Get-CreateRule).Definition)

            foreach($user in $PrimarySmtpAddress){

             try{ 


                                $i = Get-Mailbox $user.nnumber | select primarysmtpaddress, alias #extract primarysmtp and alias

                                $alias = $i.primarysmtpaddress



                                $id = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId -ArgumentList "SmtpAddress",$alias   #using Impersonation to create rule
                                $ExchangeService.ImpersonatedUserId = $id

                                $ExchangeService.AutodiscoverUrl($alias)              

                }catch{

                    $errcond = $_.Exception.Message
                    $timestamp = (get-date).DateTime
                    "Time of exception:  $timestamp" | Out-File $LogFile -Append
                    "User: $user" | out-file $LogFile -Append
                    $errcond | out-file -FilePath $LogFile -append
                }


                $i = $null

              $PowershellThread = [powershell]::Create().AddScript($ScriptBlock)
              $PowershellThread.AddArgument($alias) | Out-Null

              $PowershellThread.AddArgument($ExchangeService) | Out-Null

              $PowershellThread.RunspacePool = $RunspacePool
    $Handle = $PowershellThread.BeginInvoke()
    $Job = "" | Select-Object Handle, Thread, object
    $Job.Handle = $Handle
    $Job.Thread = $PowershellThread
    $Job.Object = $user #.ToString()
    $Jobs += $Job

                $alias = $null
            }

        }    
    }



      end{ 
            $results = @()
            if($MultiThread)
            {
                While (@($Jobs | Where-Object {$_.Handle -ne $Null}).count -gt 0)  {
                   ForEach ($Job in $($Jobs | Where-Object {$_.Handle.IsCompleted -eq $True})){
        $results+=$Job.Thread.EndInvoke($Job.Handle)
        $Job.Thread.Dispose()
        $Job.Thread = $Null
        $Job.Handle = $Null

            }   

                }
                $results
                $RunspacePool.Close() | Out-Null
            $RunspacePool.Dispose() | Out-Null
            }


      }       



                                                                                                                                                                                                                                                                                                                                                                                                   
    Friday, July 27, 2018 5:19 PM

Answers

  • The ExchangeService Object isn't thread safe so you would need to create a new instance of ExchangeService for every thread you initiate rather then the way your just passing one instance in which is why the last user is the only one that is working.

    I wouldn't recommend you run that code at all it just spins up as many threads as it can without consideration for the Server. You should limit the total threads to under 10 at time else all this will do is either get throttled or if you disable throttling cause the server to run slow or crash


     
    • Marked as answer by nickkinn Thursday, August 2, 2018 2:12 PM
    Monday, July 30, 2018 3:05 AM

All replies

  • Correction - it does properly pass each users smtp address into the function  - but only deletes the last persons inbox rules in the list of users on the csv file for some reason - used without multithreading it works fine

    its something to do with this operation:

    if($rule.displayname -eq 'Redirect1')
                {

                    $delrule = $rule.Id
                    $RuleOperation = [Microsoft.Exchange.WebServices.Data.DeleteRuleOperation]::new($delrule)
    $ExchangeService.UpdateInboxRules([Microsoft.Exchange.WebServices.Data.RuleOperation[]]@($RuleOperation), $true)

                }
                if($rule.displayname -eq 'DL Redirect1')
                {

                    $delrule1 = $rule.Id
                    $RuleOperation = [Microsoft.Exchange.WebServices.Data.DeleteRuleOperation]::new($delrule1)
    $ExchangeService.UpdateInboxRules([Microsoft.Exchange.WebServices.Data.RuleOperation[]]@($RuleOperation), $true)

                }

         but its very hard to debug with the multithreading  - would any one have any ideas?

    Here is the full function - cannot figure this out why it only does the last person on the list - i have write hosts - so i see it printing out the rules of the person for debugging but the write-hosts are not correct either last person on the list piped in has more rules outputted than everyone else even though they dont have that many - its somehow been appended or something somewhere

    process {
       
      function Get-DeleteRule()
      {
           param(
               $alias,  
            [Microsoft.Exchange.WebServices.Data.ExchangeService]$exchangeService
         

           )  

        

        write-host -ForegroundColor DarkBlue "DEF in function"
        write-host -ForegroundColor DarkGreen $alias
        

            $rules = $ExchangeService.GetInboxRules($alias.tostring())
            
          foreach($rule in $rules)
            {
                #Write-Host -ForegroundColor DarkGreen $rule.displayname
                if($rule.displayname -eq 'Redirect1')
                {
                    
                    [string]$delrule = $rule.Id
    Write-Host -ForegroundColor DarkGreen $delrule
    Write-Host -ForegroundColor DarkGreen $rule.displayname
                    $RuleOperation = [Microsoft.Exchange.WebServices.Data.DeleteRuleOperation]::new([string]$delrule)
                    $ExchangeService.UpdateInboxRules([Microsoft.Exchange.WebServices.Data.RuleOperation[]]@($RuleOperation), $true)
                    
                }
                if($rule.displayname -eq 'DL Redirect1')
                {

                    [string]$delrule1 = $rule.Id
    Write-Host -ForegroundColor DarkGreen $delrule
    Write-Host -ForegroundColor DarkGreen $rule.displayname
                
                    $RuleOperation = [Microsoft.Exchange.WebServices.Data.DeleteRuleOperation]::new([string]$delrule1)
                    $ExchangeService.UpdateInboxRules([Microsoft.Exchange.WebServices.Data.RuleOperation[]]@($RuleOperation), $true)
                                
                    

                }

               

           
            }


          

      }

           


    • Edited by nickkinn Monday, July 30, 2018 2:06 AM clarity
    Monday, July 30, 2018 1:17 AM
  • The ExchangeService Object isn't thread safe so you would need to create a new instance of ExchangeService for every thread you initiate rather then the way your just passing one instance in which is why the last user is the only one that is working.

    I wouldn't recommend you run that code at all it just spins up as many threads as it can without consideration for the Server. You should limit the total threads to under 10 at time else all this will do is either get throttled or if you disable throttling cause the server to run slow or crash


     
    • Marked as answer by nickkinn Thursday, August 2, 2018 2:12 PM
    Monday, July 30, 2018 3:05 AM
  • Hi Glenn

    I had no idea about that - not sure what you mean by "the ExchangeService Object isn't thread safe so you would need to create a new instance of ExchangeService for every thread you initiate " - what does thread safe mean?

    But it seems to have done the trick - it now deletes the rules for every user - however the write-host still prints out more rules than every other user and more than the user has for some reason?

    see below the output

    .\exdevdeleterulemt.ps1 -MultiThread
    cmdlet Get-Credential at command pipeline position 1
    Supply values for the following parameters:
    Alias is extest@exdevtest.com
    DEF in function
    extest@exdevtest.com
    Alias is extest1@exdevtest1.com
    DEF in function
    extest1@exdevtest1.com
    AQAAABQwe2M=
    Redirect1
    AQAAABQrq34=
    Redirect1
    Alias is extest2@exdevtest2.com
    AQAAABQwe2M=
    AQAAABQrq34=
    DL Redirect1
    DEF in functionDL Redirect1

    extest2@exdevtest2l.com
    AQAAABQrq34=
    DL Redirect1
    AQAAABQwe2M=
    AQAAABOQbBY=
    Redirect1
    DL Redirect1
    AQAAABQrq3g=
    Redirect1
    AQAAABQwe10=
    Redirect1
    AQAAABOQbBY=
    DL Redirect1
    AQAAABQrq3g=
    DL Redirect1
    AQAAABQwe10=
    DL Redirect1
    AQAAABQrq3w=
    Redirect1
    AQAAABOQbBY=
    DL Redirect1
    AQAAABQwe2E=
    Redirect1
    AQAAABQrq3w=
    DL Redirect1
    AQAAABQwe2E=
    DL Redirect1
    AQAAABOQbBA=
    Redirect1
    AQAAABQrq3o=
    Redirect1
    AQAAABQwe18=
    Redirect1
    AQAAABOQbBA=
    DL Redirect1
    AQAAABOQbBQ=
    Redirect1
    AQAAABOQbBQ=
    DL Redirect1
    AQAAABOQbBI=
    Redirect1

    I have this line of code in the Begin block to limit the thread to 10 i think

    $RunspacePool = [RunspaceFactory]::CreateRunspacePool(1, 10,$Sessionstate, $Host)
            $RunspacePool.ApartmentState = "STA"
            $RunspacePool.Open()

    Thanks so much btw - this has fixed it at least!

    so I am creating the Exchange Service object inside the foreach loop like this now instead of 1 time at the top in the begin loop

    foreach($user in $PrimarySmtpAddress){

             try{ 
                        

                                $i = Get-Mailbox $user.nnumber | select primarysmtpaddress, alias #extract primarysmtp and alias
                                
                                $alias = $i.primarysmtpaddress

                                
                                $Exchangeservice = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService
                                $ExchangeService.credentials = $cred
                                $id = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId -ArgumentList "SmtpAddress",$alias  #using Impersonation to create rule
                                $ExchangeService.ImpersonatedUserId = $id

    $ExchangeService.AutoDiscoverUrl($alias)

    }

    Monday, July 30, 2018 10:00 AM
  • Its wierd for the opposite - the Create Rule operation - I only create one instance for the ExchangeService object - using multithreading and it creates the 2 rules fine for every user?
    Monday, July 30, 2018 10:09 AM