Outlook Powershell Questions

This topic contains 7 replies, has 5 voices, and was last updated by  Aaron 1 day, 23 hours ago.

  • Author
    Posts
  • #99027

    Aaron
    Participant

    I have a task I want performed but I wasn't sure if powershell had the capabilities to do it.

    What I'm essentially wanting is something that will monitor an exchange mailbox and whenever an email comes in with an attachment it will strip the attachment and save it to a directory, and if the mailbox gets an email without an attachment it saves the email as a text file to a directory.

    Can this task be accomplished with powershell? And if so can anyone point me in the right direction?

    Thanks!

  • #99031

    Don Jones
    Keymaster

    I'd rate this a very poor use case for PowerShell. It could be done, but PowerShell isn't designed as a background monitoring service, and the modules available for getting into a mailbox are few and far between. This'd be far better as a .NET-written service that taps into Exchange's own event loop, rather than having to continually log into a mailbox and scan for new messages.

    PowerShell as any kind of "monitoring tool" isn't a stunning way to start the day, IMO.

  • #99037

    Dave Brannan
    Participant

    As Don said, this is possible with PowerShell using EWS, and a PowerShell script can be invoked on startup as a scheduled task to act like a "service" if need. I've done both but probably would be better as an Exchange Transport Agent.

    This approach however has its own considerations as you need to be careful with the C# code as you can easily crash the transport service.

  • #99039

    Aaron
    Participant

    It probably wouldn't be real time, but more of a 'scan the mailbox every hour, anything with attachment pull them and put them in location XYZ then delete email, anything without an attachment strip to text and put in directory ABC then delete email'.

    I dont know if that makes it a better case for powershell or not

  • #99045

    Mark Prior
    Participant

    i actually do this very thing with PS, however i also utilise microsoft orchestrator to do the monitoring

    
    $olFolderInbox = 6 
    $outlook = new-object -com outlook.application; 
    $ns = $outlook.GetNameSpace("MAPI"); 
    $inbox = $ns.GetDefaultFolder($olFolderInbox)
    $messages = $inbox.items 
    $messcount = $messages.count 
    
    
    
    
    foreach($message in $messages){ 
    
    
    ##############Save Attachments################
    
    $filepath = "c:\temp\moodle\" 
    $message.attachments|foreach { 
        Write-Host $_.filename 
        $attr = $_.filename 
    
        $_.saveasfile((Join-Path $filepath $_.filename))
    
        $a = $_.filename 
        If ($a.Contains("")) { 
        $_.saveasfile((Join-Path $filepath $a)) 
                                 } 
      } 
    
    
    Search-Mailbox "sender" -SearchQuery "from:moodle@domain.com" -DeleteContent -Force
    
    

    may take some fettling to suite your needs but will be a start, for this example i expect a mail every hours with an attachment. and i am only interested in one mail at a time hence removing the mails at the end.

  • #99052

    Aaron
    Participant

    I appreciate the help Mark! Unfortunetly this is a shared mailbox that I don't actually connect to via Outlook but was looking for a way to do this on the exchange side.

    I'm using the below code to just query my mailboxes last 10 emails, but I'm not sure if theres a way to write each to a text file

    param($mailboxName = "name@domain.com",
    $smtpServerName = "8.8.8.8"
    )
     
    # Load the EWS Managed API
    Add-Type -Path "C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll"
     
      $Exchange2016 = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2016
      
      # create EWS Service object for the target mailbox name
      $exchangeService = New-Object -TypeName Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList $Exchange2016
      
      $exchangeService.UseDefaultCredentials = $true
      $exchangeService.AutodiscoverUrl($mailboxName)
     
      # bind to the Inbox folder of the target mailbox
      $inboxFolderName = [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox
      $inboxFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($exchangeService,$inboxFolderName)
     
      # Optional: reduce the query overhead by viewing the inbox 10 items at a time
      $itemView = New-Object -TypeName Microsoft.Exchange.WebServices.Data.ItemView -ArgumentList 10
      # search the mailbox for messages older than 15 minutes
      $dateTimeItem = [Microsoft.Exchange.WebServices.Data.ItemSchema]::DateTimeReceived
      $15MinutesAgo = (Get-Date).AddMinutes(-15)
      $searchFilter = New-Object -TypeName Microsoft.Exchange.WebServices.Data.SearchFilter+IsLessThanOrEqualTo -ArgumentList $dateTimeItem,$15MinutesAgo
      $foundItems = $exchangeService.FindItems($inboxFolder.Id,$searchFilter,$itemView)
    

    With $foundItems I thought I would be able to see the body/save attachments but I'm not able to do either (from what I can tell)

      foreach($item in $foundItems)
      {
    	#displays nothing
    	$item.body
      
    	if($item.hasattachments)
    	{
    		#somehow save attachment to a file location..but unsure how
    	}
    	else
    	{
    		#save the email as a text file to a file location
    	}
      }
    
    
  • #99057

    Joel Sallow
    Participant

    Try doing $Item | Get-Member — that will show you exactly what properties and methods are available for you to pull from. 🙂

  • #99090

    Aaron
    Participant

    Hey guys,

    Figured out a way if anyone is interested...for me this will be a daily task that cleans out a mailbox by finding all the emails with attachments and strips the attachment and saves it to a directory and all emails without attachments (which the body is a identical to the attachments in the other emails) and saves it as text to another directory.

    Thanks for the help guys

    # Name of the mailbox to pull attachments from
    $MailboxName = 'mailbox@domain.com'
     
    # Location to move attachments
    $downloadDirectory = '\\wheverever\attachmentdirectory\'
     
    # Path to the Web Services dll
    $dllpath = "C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll"
    [VOID][Reflection.Assembly]::LoadFile($dllpath)
     
    # Create the new web services object
    $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2016)
     
    # Create the LDAP security string in order to log into the mailbox
    $sidbind = "LDAP://"
    $aceuser = [ADSI]$sidbind
     
    # Auto discover the URL used to pull the attachments
    $service.AutodiscoverUrl($aceuser.mail.ToString())
     
    # Get the folder id of the Inbox
    $folderid = new-object  Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox,$MailboxName)
    $InboxFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid)
    
    $view = new-object Microsoft.Exchange.WebServices.Data.ItemView(2000)
    $frFolderResult = $InboxFolder.FindItems($view)
     
     #Gets the properties of the body in text form, not html
    $PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
    $PropertySet.RequestedBodyType = [Microsoft.Exchange.WebServices.Data.BodyType]::Text 
     
    # Loop through the emails
    foreach ($miMailItems in $frFolderResult.Items){
    	
    	if($miMailItems.HasAttachments)
    	{
    		# Load the message with a TEXT body
    		$miMailItems.Load($propertySet)
    	 
    		# Loop through the attachments
    		foreach($attach in $miMailItems.Attachments){
    	 
    			# Load the attachment
    			$attach.Load()
    	 
    			# Save the attachment to the predefined location
    			$fiFile = new-object System.IO.FileStream(($downloadDirectory + “\” + (Get-Date).Millisecond + "_" + $attach.Name.ToString()), [System.IO.FileMode]::Create)
    			$fiFile.Write($attach.Content, 0, $attach.Content.Length)
    			$fiFile.Close()
    		}
    	}
    	else
    	{
    		# Load the message with a TEXT body
    		$miMailItems.Load($propertySet)
    		#path is whatever\subject_time
    		$Name = "$($miMailItems.subject)_$(get-date($miMailItems.DateTimeReceived) -Format MMddyyy_HHmmss).txt"
    		
    		$Name = $Name -replace [Regex]::Escape("["), ""
    		$Name = $Name -replace [Regex]::Escape("]"), ""
    		$Name = $Name -replace [Regex]::Escape(":"), ""
    		$Name = $Name -replace ";", ""
    		
    		$path = ("\\SERVER\EMAIL_AS_TEXT\" + $Name)
    		$miMailItems.body.text | Out-File $path
    	}
        # Mark the email as read
    	$miMailItems.isread = $true
        $miMailItems.Update([Microsoft.Exchange.WebServices.Data.ConflictResolutionMode]::AlwaysOverwrite)
     
        #Delete the message (optional)
        [VOID]$miMailItems.Move("DeletedItems")
    }
    

You must be logged in to reply to this topic.