Connect to Exchange 2016 / EWS (Export UM wav file)

Welcome Forums General PowerShell Q&A Connect to Exchange 2016 / EWS (Export UM wav file)

Viewing 2 reply threads
  • Author
    Posts
    • #193174
      Participant
      Topics: 1
      Replies: 0
      Points: 13
      Rank: Member

      Hello –

      I'm brand new to this forum, and was hoping to get some guidance.  We recently began migrating users from Exchange UM to XMedius (AVST), but in the process got some users that are a bit annoyed that they need to re-record their greeting.  I was able to get a script to work that will get one user at a time, but what I'd ultimately like is for this to look at the whole organization for any user who is UM enabled, see if they have the Standard Greeting, and then save it to a location.  Whether I call for every UM enabled mailbox by Get-UMMailbox, or I import from a csv file, that works.  I've provided the script that I've found on the web (One Simple Script) and what I was thinking.  Any positive thoughts are welcome.

      # Parameters for the script
      [CmdletBinding(DefaultParametersetName = "Common")]
      param(
          [Parameter(Mandatory = $true)] $User,
          [switch] $SaveAudio,
          [string] $Path
      )
      
      #Get Creds - Global Administrator prefered
      #$UserCredential = Get-Credential
      #Import API DLL
      $dllpath = 'C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll'
      Import-Module $dllpath
      #Connect To Exchange 2016
      #$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://domain.com/powershell/ -Credential $UserCredential -Authentication Kerberos -AllowRedirection
      #Import-PSSession $Session -AllowClobber
      #Set Global Admmin User used to login to exchange online above To Allow Application Impersonation to use EWS So This Thing Works!
      #Enable-OrganizationCustomization -ErrorAction SilentlyContinue
      #New-ManagementRoleAssignment -Role "ApplicationImpersonation" -User $UserCredential.UserName
      
      #Setup User Impersonation for the $Service variable
      $ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2016
      ## Define UPN of the Account that has impersonation rights
      $AccountWithImpersonationRights = $UserCredential.UserName
      ## Create Exchange Service Object
      $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($ExchangeVersion)
      #Get valid Credentials using UPN for the ID that is used to impersonate mailbox
      $psCred = $UserCredential
      $creds = New-Object System.Net.NetworkCredential($psCred.UserName.ToString(), $psCred.GetNetworkCredential().password.ToString())
      $service.Credentials = $creds
      ########Set the URL of the CAS (Client Access Server) #######
      $service.Url = new-object Uri("https://owa.domain.com/ews/exchange.asmx")
      
      # Get the UM mailbox
      if ( !($Mailbox = Get-Mailbox $User -ErrorAction SilentlyContinue) ) {
          throw "Mailbox could not be found for user '$($User)'."
      }
      
      if ( $Mailbox.Count -gt 1 ) {
          throw "Multiple mailboxes found. Input must be a unique mail-enabled user."
      }
      
      If ( $SaveAudio -and -not($Path) ) {
          throw "Path must be specified when -SaveAudio is set"
      }
      
      If ( $Path ) {
          If (-not (Test-Path $Path) ) {
              Throw "Path does not exist!"
          }
          If (-not ((Get-Item $Path) -is [System.IO.DirectoryInfo])) {
              Throw "Path must be to a directory!"
          }
      
      }
      
      # Get the SMTP address from the mailbox
      $SmtpAddress = $Mailbox.PrimarySmtpAddress.ToString()
      
      # Use EWS Impersonation to locate the root folder in the mailbox
      $Service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $SmtpAddress)
      $FolderId = [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root
      $Folder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($Service, $FolderId)
      
      If (-not $Folder) {
          Throw "Unable to bind to mailbox root folder"
      }
      
      # Create the search filter to find the UM custom greetingsd
      $searchFilter = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+ContainsSubstring([Microsoft.Exchange.WebServices.Data.ItemSchema]::ItemClass, "IPM.Configuration.Um.CustomGreetings", [Microsoft.Exchange.WebServices.Data.ContainmentMode]::Substring, [Microsoft.Exchange.WebServices.Data.ComparisonMode]::IgnoreCase);
      
      # Define the EWS search view
      $view = New-Object Microsoft.Exchange.WebServices.Data.ItemView(100, 0, [Microsoft.Exchange.WebServices.Data.OffsetBasePoint]::Beginning)
      $view.PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
      $view.Traversal = [Microsoft.Exchange.WebServices.Data.ItemTraversal]::Associated
      
      # Create the object to return
      $Output = New-Object System.Object
      $Output | Add-Member -type NoteProperty -name "DisplayName" -value $Mailbox.DisplayName
      $Output | Add-Member -type NoteProperty -name "PrimarySmtpAddress" -value $SmtpAddress
      $Output | Add-Member -type NoteProperty -name "HasCustomVoicemailGreeting" -value $False
      $Output | Add-Member -type NoteProperty -name "VoicemailGreetingModifiedDate" -value $Null
      $Output | Add-Member -type NoteProperty -name "HasCustomAwayGreeting" -value $False
      $Output | Add-Member -type NoteProperty -name "AwayGreetingModifiedDate" -value $Null
      
      # Do the search and enumerate the results
      If ($results = $service.FindItems( $FolderId, $searchFilter, $view )) {
          If ($SaveAudio) {
              # Define the property set required to get the binary audio data
              $psPropset = new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
      
              # Add the binary audio data property to the property set
              $PidTagRoamingBinary = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x7C09, [Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary);
              $psPropset.Add($PidTagRoamingBinary)
      
              # Load the new properties
              [Void]$service.LoadPropertiesForItems($results, $psPropset)
          }
      
          # Loop through the results
          $Item = $Null
          ForEach ($Item in $Results.Items) {
              # If this is the main greeting, set the flag to true
              If ($Item.ItemClass -eq "IPM.Configuration.Um.CustomGreetings.External" ) {
                  $Output.HasCustomVoicemailGreeting = $True
                  $Output.VoicemailGreetingModifiedDate = $Item.LastModifiedTime
                  $Filename = $Mailbox.Name + "_Standard.wav"
              }
      
              # If this is the extended away greeting, set the flag to true
              If ($Item.ItemClass -eq "IPM.Configuration.Um.CustomGreetings.Oof" ) {
                  $Output.HasCustomAwayGreeting = $True
                  $Output.AwayGreetingModifiedDate = $Item.LastModifiedTime
                  $Filename = $Mailbox.Name + "_Extended.wav"
              }
      
              If ($SaveAudio) {
                  # Write the audio data to the file
                  [IO.File]::WriteAllBytes("$Path\$Filename", $Item.ExtendedProperties.Value)
              }
          }
      }
      
      return $Output
      
    • #193216
      Senior Moderator
      Topics: 8
      Replies: 1153
      Points: 4,006
      Helping Hand
      Rank: Community Hero

      Hi, just wanted to let you know that I've reformatted the code you posted following the guide lines. Please find below the instructions to format the code in the forum.

      https://powershell.org/forums/topic/read-me-before-posting-youll-be-glad-you-did/

    • #193300
      Participant
      Topics: 10
      Replies: 1381
      Points: 1,509
      Helping Hand
      Rank: Community Hero

      Just started playing with the EWS API, I've not seen a way to search All mailboxes with filter, everything I've seen is connecting to a single mailbox. With that said, you'd probably need to create a wrapper around the code that is getting information around every mailbox, something like this:

      # Parameters for the script
      # [CmdletBinding(DefaultParametersetName = "Common")]
      # param(
      #     [Parameter(Mandatory = $true)] $User,
      #     [switch] $SaveAudio,
      #     [string] $Path
      # )
      
      #Get Creds - Global Administrator prefered
      $UserCredential = Get-Credential
      #Import API DLL
      $dllpath = 'C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll'
      Import-Module $dllpath
      #Connect To Exchange 2016
      $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://domain.com/powershell/ -Credential $UserCredential -Authentication Kerberos -AllowRedirection
      Import-PSSession $Session -AllowClobber
      #Set Global Admmin User used to login to exchange online above To Allow Application Impersonation to use EWS So This Thing Works!
      Enable-OrganizationCustomization -ErrorAction SilentlyContinue
      New-ManagementRoleAssignment -Role "ApplicationImpersonation" -User $UserCredential.UserName
      
      #Setup User Impersonation for the $Service variable
      $ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2016
      ## Define UPN of the Account that has impersonation rights
      $AccountWithImpersonationRights = $UserCredential.UserName
      ## Create Exchange Service Object
      $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($ExchangeVersion)
      #Get valid Credentials using UPN for the ID that is used to impersonate mailbox
      $psCred = $UserCredential
      $creds = New-Object System.Net.NetworkCredential($psCred.UserName.ToString(), $psCred.GetNetworkCredential().password.ToString())
      $service.Credentials = $creds
      ########Set the URL of the CAS (Client Access Server) #######
      $service.Url = new-object Uri("https://owa.domain.com/ews/exchange.asmx")
      
      # Get the UM mailbox
      # if ( !($Mailbox = Get-Mailbox $User -ErrorAction SilentlyContinue) ) {
      #     throw "Mailbox could not be found for user '$($User)'."
      # }
      
      # if ( $Mailbox.Count -gt 1 ) {
      #     throw "Multiple mailboxes found. Input must be a unique mail-enabled user."
      # }
      
      # If ( $SaveAudio -and -not($Path) ) {
      #     throw "Path must be specified when -SaveAudio is set"
      # }
      
      # If ( $Path ) {
      #     If (-not (Test-Path $Path) ) {
      #         Throw "Path does not exist!"
      #     }
      #     If (-not ((Get-Item $Path) -is [System.IO.DirectoryInfo])) {
      #         Throw "Path must be to a directory!"
      #     }
      
      # }
      
      $mailboxes = Get-MailBox -Filter *
      
      $results = foreach ( $mailbox in $mailboxes ) {
          # Get the SMTP address from the mailbox
          $SmtpAddress = $Mailbox.PrimarySmtpAddress.ToString()
      
          # Use EWS Impersonation to locate the root folder in the mailbox
          $Service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $SmtpAddress)
          $FolderId = [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root
          $Folder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($Service, $FolderId)
      
          If (-not $Folder) {
              Throw "Unable to bind to mailbox root folder"
          }
      
          # Create the search filter to find the UM custom greetingsd
          $searchFilter = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+ContainsSubstring([Microsoft.Exchange.WebServices.Data.ItemSchema]::ItemClass, "IPM.Configuration.Um.CustomGreetings", [Microsoft.Exchange.WebServices.Data.ContainmentMode]::Substring, [Microsoft.Exchange.WebServices.Data.ComparisonMode]::IgnoreCase);
      
          # Define the EWS search view
          $view = New-Object Microsoft.Exchange.WebServices.Data.ItemView(100, 0, [Microsoft.Exchange.WebServices.Data.OffsetBasePoint]::Beginning)
          $view.PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
          $view.Traversal = [Microsoft.Exchange.WebServices.Data.ItemTraversal]::Associated
      
          # Create the object to return
          $Output = New-Object System.Object
          $Output | Add-Member -type NoteProperty -name "DisplayName" -value $Mailbox.DisplayName
          $Output | Add-Member -type NoteProperty -name "PrimarySmtpAddress" -value $SmtpAddress
          $Output | Add-Member -type NoteProperty -name "HasCustomVoicemailGreeting" -value $False
          $Output | Add-Member -type NoteProperty -name "VoicemailGreetingModifiedDate" -value $Null
          $Output | Add-Member -type NoteProperty -name "HasCustomAwayGreeting" -value $False
          $Output | Add-Member -type NoteProperty -name "AwayGreetingModifiedDate" -value $Null
      
          # Do the search and enumerate the results
          If ($results = $service.FindItems( $FolderId, $searchFilter, $view )) {
              If ($SaveAudio) {
                  # Define the property set required to get the binary audio data
                  $psPropset = new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
      
                  # Add the binary audio data property to the property set
                  $PidTagRoamingBinary = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x7C09, [Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary);
                  $psPropset.Add($PidTagRoamingBinary)
      
                  # Load the new properties
                  [Void]$service.LoadPropertiesForItems($results, $psPropset)
              }
      
              # Loop through the results
              $Item = $Null
              ForEach ($Item in $Results.Items) {
                  # If this is the main greeting, set the flag to true
                  If ($Item.ItemClass -eq "IPM.Configuration.Um.CustomGreetings.External" ) {
                      $Output.HasCustomVoicemailGreeting = $True
                      $Output.VoicemailGreetingModifiedDate = $Item.LastModifiedTime
                      $Filename = $Mailbox.Name + "_Standard.wav"
                  }
      
                  # If this is the extended away greeting, set the flag to true
                  If ($Item.ItemClass -eq "IPM.Configuration.Um.CustomGreetings.Oof" ) {
                      $Output.HasCustomAwayGreeting = $True
                      $Output.AwayGreetingModifiedDate = $Item.LastModifiedTime
                      $Filename = $Mailbox.Name + "_Extended.wav"
                  }
      
                  If ($SaveAudio) {
                      # Write the audio data to the file
                      [IO.File]::WriteAllBytes("$Path\$Filename", $Item.ExtendedProperties.Value)
                  }
              }
          }
      
          return $Output
      }
      
      $results
      
Viewing 2 reply threads
  • You must be logged in to reply to this topic.