EWS.psm1
param ( [string]$Mailbox = 'bartek.bielawski@live.com', [Microsoft.Exchange.WebServices.Data.ExchangeVersion]$Version = 'Exchange2010_SP1' ) <# Still TODO: -- commment based help for functions -- about_ article to describe functionality #> $connections = @{} function Connect-EWSService { [OutputType('Microsoft.Exchange.WebServices.Data.ExchangeService')] [CmdletBinding()] param ( # Mailbox that command will connect to. $Mailbox = $Script:Mailbox, # Version of exchange server that we will connect to. [Microsoft.Exchange.WebServices.Data.ExchangeVersion] $Version = $Script:Version, # Credentials that will be used to connect to mailbox. [Management.Automation.PSCredential] [Management.Automation.Credential()] $Credential = [Management.Automation.PSCredential]::Empty ) $exchangeService = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService $Version if ($Credential -ne [Management.Automation.PSCredential]::Empty) { $exchangeService.UseDefaultCredentials = $false $exchangeService.Credentials = $Credential.GetNetworkCredential() } else { $exchangeService.UseDefaultCredentials = $true } $exchangeService.AutodiscoverUrl($Mailbox) $Script:exchangeService = $exchangeService $Script:connections.Add( $exchangeService, $Mailbox ) $exchangeService } function Get-EWSItem { [OutputType('Microsoft.Exchange.WebServices.Data.Item')] [CmdletBinding( DefaultParameterSetName = 'byId' )] param ( # Filter that will be used to retrieve items. [Parameter(Position = 0)] [string]$Filter, # Id of folder that items will be retrieved from. [Parameter( ParameterSetName = 'byId', ValueFromPipelineByPropertyName = $true, Mandatory = $true )] [Microsoft.Exchange.WebServices.Data.FolderId]$Id, # [Parameter( ParameterSetName = 'byName', Mandatory = $true )] [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]$Name, # Service object that will be used to retrieve items. [Parameter( ValueFromPipelineByPropertyName = $true )] [Microsoft.Exchange.WebServices.Data.ExchangeService]$Service = $Script:exchangeService, [Microsoft.Exchange.WebServices.Data.BasePropertySet]$PropertySet, [ValidateRange(1,1000)] [Int]$PageSize = 100, [Int]$Limit ) process { if (-not $Service) { return } switch ($PSCmdlet.ParameterSetName) { byId { $secondParameter = $Id } byName { $secondParameter = $Name } } $folder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind( $Service, $secondParameter ) if ($Limit -and $Limit -lt $PageSize) { $PageSize = $Limit } $view = New-Object Microsoft.Exchange.WebServices.Data.ItemView $PageSize, 0 do { $list = $Folder.FindItems($Filter,$view) if ($PropertySet -and $Lista.TotalCount) { $set = New-Object Microsoft.Exchange.WebServices.Data.PropertySet $PropertySet $Service.LoadPropertiesForItems( $list, $set ) | Out-Null } $list $view.Offset += $list.Items.Count if ($Widok.Offset -ge $Limit) { break } } while ($list.MoreAvailable) } end { if (-not $Service) { Write-Warning 'No connection defined. Use Connect-EWSService first!' } } } function Get-EWSFolder { [OutputType('Microsoft.Exchange.WebServices.Data.Folder')] [CmdletBinding()] param ( [Parameter( Mandatory = $true )] [ValidateScript({ $Root, $Rest = $_ -split '\\|/|:|\|' try { [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]$Root $true } catch { throw "Root folder must belong to collection of WellKnownFolderName: $_" } })] [string]$Path, [Microsoft.Exchange.WebServices.Data.ExchangeService]$Service = $Script:exchangeService, [Microsoft.Exchange.WebServices.Data.Mailbox]$Mailbox ) if (-not $Service) { Write-Warning 'No connection defined. Use Connect-EWSService first!' return } if (-not $PSBoundParameters.ContainsKey('Mailbox')) { if (-not ($Mailbox = $connections[$Service])) { $Mailbox = $Script:Mailbox } } $name = [Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName $rootFolderName, $remaingPath = $Path -split '\\|/|:|\|' try { $rootFolder = New-Object Microsoft.Exchange.WebServices.Data.FolderId $rootFolderName, $Mailbox } catch { throw "Unexpected error occured: $_" } $root = [Microsoft.Exchange.WebServices.Data.Folder]::Bind( $Service, $rootFolder ) foreach ($item in $remaingPath) { $filter = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo -ArgumentList @( $name, $item ) $lastItem = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+ContainsSubstring -ArgumentList @( $name, $item ) try { $new = $root.FindFolders($filter,1).Folders[0] if ($new) { $root = $new } else { $view = New-Object Microsoft.Exchange.WebServices.Data.FolderView 10, 0 do { $list = $root.FindFolders($lastItem,$view) $list $view.Offset += $list.Items.Count } while ($list.MoreAvailable) } } catch { Write-Warning "Could not find subfolder: $item" $root return } } $root } function Get-EWSAttachment { [OutputType('Microsoft.Exchange.WebServices.Data.FileAttachment')] [CmdletBinding()] param ( [Parameter( ValueFromPipeline = $true )] [Microsoft.Exchange.WebServices.Data.Item[]]$Item, [Parameter( ValueFromPipelineByPropertyName = $true )] [Microsoft.Exchange.WebServices.Data.ExchangeService]$Service = $script:exchangeService ) end { if (-not $Service) { Write-Warning 'No connection defined. Use Connect-EWSService first!' } } process { if (-not $Service) { return } $Service.LoadPropertiesForItems( $Item, [Microsoft.Exchange.WebServices.Data.PropertySet]::FirstClassProperties ) | Out-Null foreach ($singleItem in $Item) { foreach ($attachment in $singleItem.Attachments) { $attachment } } } } function Save-EWSAttachment { [CmdletBinding( SupportsShouldProcess = $true, ConfirmImpact = 'Low' )] param ( [string]$Path, [Parameter( ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true )] [Microsoft.Exchange.WebServices.Data.FileAttachment[]]$Attachment, [Parameter( ValueFromPipelineByPropertyName = $true )] [Microsoft.Exchange.WebServices.Data.ExchangeService]$Service = $script:exchangeService ) end { if (-not $Service) { Write-Warning 'No connection defined. Use Connect-EWSService first!' } } process { if (-not $Service) { return } foreach ($singleAttachment in $Attachment) { $fullPath = Join-Path -Path $Path -ChildPath $singleAttachment.Name if ($PSCmdlet.ShouldProcess( $singleAttachment.Name, "Save to $Path" )) { $singleAttachment.Load( $fullPath ) } } } } function New-EWSMessage { [OutputType('Microsoft.Exchange.WebServices.Data.EmailMessage')] [CmdletBinding( DefaultParameterSetName = 'inline' )] param ( [Parameter( Mandatory = $true )] [string[]]$To, [string[]]$Cc, [string[]]$Bcc, [Parameter( Mandatory = $true )] [string]$Subject, [Parameter( Mandatory = $true, ParameterSetName = 'inline' )] [string]$Body, [Microsoft.Exchange.WebServices.Data.BodyType]$BodyType = 'Text', [string[]]$Attachment, [Parameter( ValueFromPipeline = $true, Mandatory = $true, ParameterSetName = 'pipe' )] $InputObject, [Parameter( ParameterSetName = 'pipe' )] [switch]$IsHtml, [Parameter( ValueFromPipelineByPropertyName = $true )] [Microsoft.Exchange.WebServices.Data.ExchangeService]$Service = $script:exchangeService ) begin { $data = New-Object Collections.ArrayList } process { if (-not $Service) { return } if ($InputObject) { $data.Add($InputObject) | Out-Null } } end { if (-not $Service) { Write-Warning 'No connection defined. Use Connect-EWSService first!' return } if ($data.Count) { if (! $IsHtml -and $BodyType -eq 'HTML') { $body = $data | ConvertTo-Html | Out-String } else { $body = $data | Out-String } } $message = New-Object Microsoft.Exchange.WebServices.Data.EmailMessage $Service $message.Subject = $Subject $message.Body = $body $message.Body.BodyType = $BodyType foreach ($file in $Attachment) { $message.Attachments.AddFileAttachment($file) | Out-Null } foreach ($recipient in $To) { $message.ToRecipients.Add( $recipient ) | Out-Null } foreach ($recipient in $Cc) { $message.CcRecipients.Add( $recipient ) | Out-Null } foreach ($recipient in $Bcc) { $message.BccRecipients.Add( $recipient ) | Out-Null } $message.SendAndSaveCopy() $message } } function New-EWSAppointment { [OutputType('Microsoft.Exchange.WebServices.Data.Appointment')] [CmdletBinding( DefaultParameterSetName = 'inline' )] param ( [string[]]$Required, [string[]]$Optional, [Parameter( Mandatory = $true )] [string]$Subject, [Parameter( Mandatory = $true, ParameterSetName = 'inline' )] [string]$Body, [Microsoft.Exchange.WebServices.Data.BodyType]$BodyType = 'Text', [string]$Location, [DateTime]$Start, [TimeSpan]$Duration, [string[]]$Attachment, [Parameter( ValueFromPipeline = $true, Mandatory = $true, ParameterSetName = 'pipe' )] $InputObject, [Parameter( ParameterSetName = 'pipe' )] [switch]$IsHtml, [Parameter( ValueFromPipelineByPropertyName = $true )] [Microsoft.Exchange.WebServices.Data.ExchangeService]$Service = $script:exchangeService ) begin { $data = New-Object Collections.ArrayList } process { if ($InputObject) { $data.Add($InputObject) | Out-Null } } end { if (-not $Service) { Write-Warning 'No connection defined. Use Connect-EWSService first!' return } if ($data.Count) { if (! $IsHtml -and $BodyType -eq 'HTML') { $body = $data | ConvertTo-Html | Out-String } else { $body = $data | Out-String } } $appointment = New-Object Microsoft.Exchange.WebServices.Data.Appointment $Service -Property @{ Subject = $Subject Body = $body Start = $Start End = $Start + $Duration Location = $Location } $appointment.Body.BodyType = $BodyType foreach ($file in $Attachment) { $appointment.Attachments.AddFileAttachment($file) | Out-Null } foreach ($attendee in $Required) { $appointment.RequiredAttendees.Add( $attendee ) | Out-Null } foreach ($attendee in $Optional) { $appointment.OptionalAttendees.Add( $attendee ) | Out-Null } if ($Required -or $Optional) { $method = [Microsoft.Exchange.WebServices.Data.SendInvitationsMode]::SendToAllAndSaveCopy } else { $method = [Microsoft.Exchange.WebServices.Data.SendInvitationsMode]::SendToNone } $appointment.Save($method) $appointment } } function New-EWSContact { [OutputType('Microsoft.Exchange.WebServices.Data.Contact')] param ( [string]$GivenName, [string]$Surname, [string]$MiddleName, [string]$Company, [ValidateScript({ try { foreach ($key in $_.Keys) { [Microsoft.Exchange.WebServices.Data.PhoneNumberKey]$key } $true } catch { throw "Error: $key - $_" } })] [hashtable]$Phone, [ValidateScript({ foreach ($hash in $_) { foreach ($key in $hash.Keys) { if ('DisplayName','email' -notcontains $key) { throw "Wrong key in e-mail hashtable: $key" } } } $true })] [hashtable[]]$Email, [ValidateScript({ try { foreach ($key in $_.Keys) { [Microsoft.Exchange.WebServices.Data.PhysicalAddressKey]$key } } catch { throw "Error: $key - $_" } foreach ($hash in $_.Values) { foreach ($key in $hash.Keys) { if ('City','CountryOrRegion','PostalCode','State','Street' -notcontains $key) { throw "Wrong key in physical address hashtable: $key" } } } $true })] [hashtable]$PhysicalAddress, [Parameter( ValueFromPipelineByPropertyName = $true )] [Microsoft.Exchange.WebServices.Data.ExchangeService]$Service = $script:ExchangeService ) if (-not $Service) { Write-Warning 'No connection defined. Use Connect-EWSService first!' return } $contact = New-Object Microsoft.Exchange.WebServices.Data.Contact $Service -Property @{ GivenName = $GivenName MiddleName = $MiddleName Surname = $Surname CompanyName = $Company FileAsMapping = [Microsoft.Exchange.WebServices.Data.FileAsMapping]::SurnameCommaGivenName } foreach ($key in $Phone.Keys) { $Contact.PhoneNumbers[$key] = $Phone.$key } $index = 1 foreach ($hash in $Email) { if ($index -le 3) { if ($email = $hash.email) { if (! ($displayName = $hash.DisplayName)) { $displayName = $hash.email } $contact.EmailAddresses["EmailAddress$index"] = New-Object Microsoft.Exchange.WebServices.Data.EmailAddress -ArgumentList @( $displayName ) $index++ } } } foreach ($key in $PhysicalAddress.Keys) { $contact.PhysicalAddresses[$key] = New-Object Microsoft.Exchange.WebServices.Data.PhysicalAddressEntry -Property @{ City = $PhysicalAddress[$key].City CountryOrRegion = $PhysicalAddress[$key].CountryOrRegion PostalCode = $PhysicalAddress[$key].PostalCode State = $PhysicalAddress[$key].State Street = $PhysicalAddress[$key].Street } } $contact.Save() $contact } function Remove-EWSFolder { [CmdletBinding( SupportsShouldProcess = $true, ConfirmImpact = 'High' )] param ( [Microsoft.Exchange.WebServices.Data.DeleteMode]$DeleteMode = 'MoveToDeletedItems', [Parameter( ValueFromPipelineByPropertyName = $true )] [Microsoft.Exchange.WebServices.Data.ExchangeService]$Service = $Script:exchangeService, [Parameter( ValueFromPipeline = $true, Mandatory = $true )] [Microsoft.Exchange.WebServices.Data.Folder]$Folder ) end { if (-not $Service) { Write-Warning 'No connection defined. Use Connect-EWSService first!' return } } process { if (-not $Service) { return } if ($PSCmdlet.ShouldProcess( "Folder: $($Folder.DisplayName)", 'Remove EWS Folder' )) { $Folder.Delete($DeleteMode) } } } function Clear-EWSFolder { [CmdletBinding( SupportsShouldProcess = $true, ConfirmImpact = 'High' )] param ( [Microsoft.Exchange.WebServices.Data.DeleteMode]$DeleteMode = 'MoveToDeletedItems', [Parameter( ValueFromPipelineByPropertyName = $true )] [Microsoft.Exchange.WebServices.Data.ExchangeService]$Service = $Script:exchangeService, [Parameter( ValueFromPipeline = $true, Mandatory = $true )] [Microsoft.Exchange.WebServices.Data.Folder]$Folder, [switch]$IncludeSubfolders ) end { if (-not $Service) { Write-Warning 'No connection defined. Use Connect-EWSService first!' return } } process { if (-not $Service) { return } if ($PSCmdlet.ShouldProcess( "Folder: $($Folder.DisplayName)", "Clear (empty) EWS Folder with$('out' * (-not $IncludeSubfolders)) subfolders" )) { $Folder.Empty($DeleteMode, $IncludeSubfolders) } } } function Remove-EWSItem { [CmdletBinding( SupportsShouldProcess = $true, ConfirmImpact = 'High' )] param ( [Microsoft.Exchange.WebServices.Data.DeleteMode]$DeleteMode = 'MoveToDeletedItems', [Parameter( ValueFromPipelineByPropertyName = $true )] [Microsoft.Exchange.WebServices.Data.ExchangeService]$Service = $Script:exchangeService, [Parameter( ValueFromPipeline = $true, Mandatory = $true )] [Microsoft.Exchange.WebServices.Data.Item]$Item ) end { if (-not $Service) { Write-Warning 'No connection defined. Use Connect-EWSService first!' return } } process { if (-not $Service) { return } if ($PSCmdlet.ShouldProcess( "Item: $($Item.Subject)", "Remove using $DeleteMode mode" )) { $Item.Delete($DeleteMode) } } } function New-EWSFolder { [OutputType('Microsoft.Exchange.WebServices.Data.Folder')] [CmdletBinding( DefaultParameterSetName = 'byName' )] param ( [Parameter( Mandatory = $true, ValueFromPipelineByPropertyName = $true )] [string]$DisplayName, [Parameter( ValueFromPipelineByPropertyName = $true )] [ValidateSet( 'Calendar', 'Contacts', 'Tasks', 'Mail' )] [string]$FolderType = 'Mail', [Parameter( ParameterSetName = 'byId', ValueFromPipelineByPropertyName = $true, Mandatory = $true )] [Alias('Id')] [Microsoft.Exchange.WebServices.Data.FolderId]$ParentId, [Parameter( ParameterSetName = 'byName', Mandatory = $true )] [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]$ParentName, [Parameter( ValueFromPipelineByPropertyName = $true )] [Microsoft.Exchange.WebServices.Data.ExchangeService]$Service = $Script:exchangeService, [Microsoft.Exchange.WebServices.Data.Mailbox]$Mailbox ) begin { $type = 'Microsoft.Exchange.WebServices.Data.{0}Folder' -f "$( if ($FolderType -ne 'Mail') { $FolderType } )" } end { if (-not $Service) { Write-Warning 'No connection defined. Use Connect-EWSService first!' return } } process { if (-not $Service) { return } if ($PSCmdlet.ParameterSetName -eq 'byName') { if (-not $PSBoundParameters.ContainsKey('Mailbox')) { if (-not ($Mailbox = $Connections[$Service])) { $Mailbox = $Script:Mailbox } } $folder = New-Object Microsoft.Exchange.WebServices.Data.FolderId $ParentName, $Mailbox $parentId = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($Service, $ParentName).Id } $newFolder = New-Object $Type $Service if ($FolderType -eq 'Mail') { $newFolder.FolderClass = 'IPF.Note' } $newFolder.DisplayName = $DisplayName $newFolder.Save($parentId) $name = [Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName $root = [Microsoft.Exchange.WebServices.Data.Folder]::Bind( $Service, $parentId ) $filter = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo -ArgumentList @( $name, $DisplayName ) try { $root.FindFolders($filter,1).Folders[0] } catch {} } } function Move-EWSItem { [CmdletBinding( ConfirmImpact = 'Medium', SupportsShouldProcess = $true )] param ( [ValidateScript({ $root, $rest = $_ -split '\\|/|:|\|' try { [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]$root $true } catch { throw "Root folder must belong to WellKnownFolderName: $_" } })] [string]$DestinationPath, [Parameter( ValueFromPipeline = $true, Mandatory = $true )] [Microsoft.Exchange.WebServices.Data.Item]$Item, [Parameter( ValueFromPipelineByPropertyName = $true )] [Microsoft.Exchange.WebServices.Data.ExchangeService]$Service = $Script:exchangeService ) end { if (-not $Service) { Write-Warning 'No connection defined. Use Connect-EWSService first!' return } } begin { $Mailbox = $Connections[$Service] $name = [Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName $rootName, $remaingPath = $DestinationPath -split '\\|/|:|\|' try { $rootId = New-Object Microsoft.Exchange.WebServices.Data.FolderId $rootName, $Mailbox } catch { throw "Unexpected error occured: $_" } $root = [Microsoft.Exchange.WebServices.Data.Folder]::Bind( $Service, $rootId ) foreach ($pathItem in $remaingPath) { $filter = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo -ArgumentList @( $name, $pathItem ) try { $new = $root.FindFolders($filter,1).Folders[0] if ($new) { $root = $new } } catch { Write-Warning "Could not find sub-folder: $pathItem" $root return } } $destination = $root } process { if (-not $Service) { return } if ($PSCmdlet.ShouldProcess( $Item.Subject, "Move to $DestinationPath" )) { $Item.Move($destination.Id) } } } function Move-EWSFolder { [CmdletBinding( ConfirmImpact = 'Medium', SupportsShouldProcess = $true )] param ( [ValidateScript({ $root, $rest = $_ -split '\\|/|:|\|' try { [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]$root $true } catch { throw "Root folder must belong to collection of WellKnownFolderName: $_" } })] [string]$DestinationPath, [Parameter( ValueFromPipeline = $true, Mandatory = $true )] [Microsoft.Exchange.WebServices.Data.Folder]$Folder, [Parameter( ValueFromPipelineByPropertyName = $true )] [Microsoft.Exchange.WebServices.Data.ExchangeService]$Service = $Script:exchangeService ) end { if (-not $Service) { Write-Warning 'No connection defined. Use Connect-EWSService first!' return } } begin { $Mailbox = $Connections[$Service] $name = [Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName $rootName, $remaingPath = $DestinationPath -split '\\|/|:|\|' try { $rootId = New-Object Microsoft.Exchange.WebServices.Data.FolderId $rootName, $Mailbox } catch { throw "Unexpected error occured: $_" } $root = [Microsoft.Exchange.WebServices.Data.Folder]::Bind( $Service, $rootId ) foreach ($pathItem in $remaingPath) { $filter = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo -ArgumentList @( $name, $pathItem ) try { $new = $root.FindFolders($filter,1).Folders[0] if ($new) { $root = $new } } catch { Write-Warning "Could not find sub-folder: $pathItem" $root return } } $destination = $root } process { if (-not $Service) { return } if ($PSCmdlet.ShouldProcess( $Folder.DisplayName, "Move to $DestinationPath" )) { $Folder.Move($destination.Id) } } } Export-ModuleMember -Function *-EWS* |