Get-Email.old.ps1
function Get-Email { <# .Synopsis Gets email from exchange .Description Gets email in an inbox using exchange web services. #> param( # If set, will only show the first N items [Parameter(ValueFromPipelineByPropertyName=$true)] [int]$First, # If set, will not get detail [Parameter(ValueFromPipelineByPropertyName=$true)] [switch]$DoNotGetDetail, # If set, will download attachments [Parameter(ValueFromPipelineByPropertyName=$true)] [Switch]$DownloadAttachment, # If set, will include only the content from this message, not the whole thread [Parameter(ValueFromPipelineByPropertyName=$true)] [switch]$ExcludeThread, # A search term. By default, the searchterm will search for the From field [Parameter(ValueFromPipelineByPropertyName=$true)] [string]$SearchTerm, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateScript({ if (-not $script:ExchangeWebService) { return $true # throw "Must Be Connected To Exchange" } $namespace = $script:exchangeWebService.GetType().Namespace $values = [Enum]::GetValues(("$namespace.UnindexedFieldURIType" -as [type])) if ($Values -notcontains $_) { throw "Search Terms Must Use On of the Following ItemTypes: $($values -join ([Environment]::NewLine))" } return $true })] [string]$SearchField = "messageFrom", # The exchange server [Parameter(ValueFromPipelineByPropertyName=$true)] [string]$ExchangeServer, # The credential used to connect [Parameter(ValueFromPipelineByPropertyName=$true)] [Management.Automation.PSCredential] $Credential, # If set, will treat the account as an Office365 account [Parameter(ValueFromPipelineByPropertyName=$true)] [Switch]$IsOffice365Account, # If set, gets email in a background job [Parameter(ValueFromPipelineByPropertyName=$true)] [Switch]$AsJob ) begin { $getExchangeItemProgressId = Get-Random function Connect-Exchange { [CmdletBinding(DefaultParameterSetName='ExchangeServer')] param( [Parameter(Mandatory=$true,Position=0,ParameterSetName='ExchangeServer')] [Parameter(Mandatory=$true,Position=0,ParameterSetName='Office365')] [Management.Automation.PSCredential] $Account, [Parameter(Mandatory=$true,Position=1,ParameterSetName='ExchangeServer')] [Parameter(Mandatory=$true,Position=1,ParameterSetName='UseDefaultCredential')] [string] $ServerName, [Parameter(Mandatory=$true,Position=1,ParameterSetName='Office365')] [Switch] $IsOffice365Account, [Parameter(Mandatory=$true,Position=1,ParameterSetName='UseDefaultCredential')] [Switch] $UseDefaultCredential, # If set, will attempt to connect to a remote powershell session as well as exchange web services [Switch] $ForAdministration ) process { if (-not $UseDefaultCredential) { if ($account.username -match "(.+)@(.+)") { $username = $matches[1] $script:hostedExchangeEmail = $account.UserName } else { $username = $account.username } } if ($psCmdlet.ParameterSetName -eq 'Office365') { if ($script:ExchangeWebService -and $script:CachedCredential.Username -eq $script:CachedCredential) { return } $ExchangeServer = "https://ps.outlook.com/" Write-Progress "Connecting to Office365" "$exchangeServer" $script:CachedCredential = $Account $MbMailbox = $account.Username $AutoDiscoURL = "https://ps.outlook.com/autodiscover/autodiscover.xml" $ncCred = New-Object Net.NetworkCredential $account.UserName,$account.GetNetworkCredential().Password $autoDiscoverXML = @" <Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006"> <Request> <EMailAddress>$MbMailbox</EMailAddress> <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema> </Request> </Autodiscover> "@; $adAutoDiscoRequest = [Net.HttpWebRequest]::Create($AutoDiscoURL) $bytes = [Text.Encoding]::UTF8.GetBytes($autoDiscoverXML ) $adAutoDiscoRequest.ContentLength = $bytes.Length $adAutoDiscoRequest.ContentType = "text/xml" $adAutoDiscoRequest.Headers.Add("Translate", "F") $adAutoDiscoRequest.Method = "POST" $adAutoDiscoRequest.Credentials = $ncCred $rsRequestStream = $adAutoDiscoRequest.GetRequestStream(); $rsRequestStream.Write($bytes, 0, $bytes.Length); $rsRequestStream.Close(); $adAutoDiscoRequest.AllowAutoRedirect = $false; $adResponse = $adAutoDiscoRequest.GetResponse(); $Redirect = $adResponse.Headers.Get("Location"); if ($Redirect) { $adAutoDiscoRequest = [Net.HttpWebRequest]::Create($Redirect); $adAutoDiscoRequest.ContentLength = $bytes.Length; $adAutoDiscoRequest.ContentType = "text/xml"; $adAutoDiscoRequest.Headers.Add("Translate", "F"); $adAutoDiscoRequest.Method = "POST"; $adAutoDiscoRequest.Credentials = $ncCred; $rsRequestStream = $adAutoDiscoRequest.GetRequestStream(); } $rsRequestStream.Write($bytes, 0, $bytes.Length); $rsRequestStream.Close(); $adResponse = $adAutoDiscoRequest.GetResponse(); $rsResponseStream = $adResponse.GetResponseStream(); $reResponseDoc = new-object Xml.XmlDocument; $reResponseDoc.Load($rsResponseStream); $pfProtocolNodes = $reResponseDoc.GetElementsByTagName("Protocol"); $finalUri = $reResponseDoc | Select-Xml //* | Where-Object {$_.Node.Name -eq 'OWAUrl' -and $_.Node.SelectSingleNode("..").Name -eq 'External' } | ForEach-Object { $_.Node.InnerText } $finalUri = $finalUri.Substring(0, $finalUri.IndexOf("/owa")) $finalUri = $finalUri + "/ews/exchange.asmx" $exchangeServer = $finalUri } else { $ExchangeServer = $ServerName } Write-Progress "Exchange Server Discovered" "$exchangeServer" $uri = "$ExchangeServer".TrimEnd('/') + '/ews/exchange.asmx' $wsdl = "$ExchangeServer".TrimEnd('/') + '/ews/services.wsdl' $script:ExchangeWebService = $null $script:ExchangeWebServiceNamespace = $null if ($finaluri) { $wsdl = "$finalUri".Replace('/ews/exchange.asmx', '/ews/services.wsdl') } if ($Account) { $script:ExchangeWebService = New-WebServiceProxy -Uri $wsdl -Credential $Account } else { $script:ExchangeWebService= New-WebServiceProxy -Uri $wsdl -UseDefaultCredential } if (-not $script:ExchangeWebService) { return } Write-Progress "Connected to Exchange!" "$exchangeServer" $script:ExchangeWebServiceNamespace = $exchangeWebService.GetType().Namespace $script:exchangeWebService.RequestServerVersionValue = New-object "$ExchangeWebServiceNamespace.RequestServerVersion" if (-not $exchangeVersion) { $exchangeVersion = ([int[]][Enum]::GetValues(("$ExchangeWebServiceNamespace.ExchangeVersionType" -as [Type]))) | Sort-Object | Select-Object -Last 1 } $script:exchangeWebService.RequestServerVersionValue.Version = ("$ExchangeWebServiceNamespace.ExchangeVersionType" -as [Type])::$exchangeVersion if ($FinalUri) { $script:exchangeWebService.Url = $finalUri } else { $script:exchangeWebService.Url = $uri } # If an account was set, make sure the web service has the credential information if ($Account) { $script:exchangeWebService.Credentials = $Account.GetNetworkCredential() } # Find the correct time zone and set it, otherwise everything comes from UTC $tzRequestType = New-Object "$ExchangeWebServiceNamespace.GetServerTimeZonesType" -Property @{ ReturnFullTimeZoneData=$true; ReturnFullTimeZoneDataSpecified=$true } $tzRequestType.Ids = "$([Timezone]::CurrentTimeZone.StandardName)" $response = $script:exchangeWebService.GetServerTimeZones($tzRequestType) # If the time zone was found, change the web service's time zone context. if ($response.responsemessages.items[0].ResponseClass -eq 'Success'){ $tzd = $response.responsemessages.items[0].timezonedefinitions $script:MyTimeZone = $tzd.TimeZoneDefinition $tzContext = New-Object "$ExchangeWebServiceNamespace.TimeZoneContextType" $tzContext.TimeZoneDefinition = $tzd.TimeZoneDefinition[0] $script:exchangeWebService.TimeZoneContext = $tzContext } if ($ForAdministration -and -not $script:administrationSession) { $newSessionParameters = @{ ConnectionUri='https://$exchangeServer/powershell' ConfigurationName='Microsoft.Exchange' Authentication='Basic' Credential=$Account AllowRedirection=$true WarningAction = "silentlycontinue" SessionOption=(New-Object Management.Automation.Remoting.PSSessionOption -Property @{OpenTimeout="00:30:00"}) } $Session = New-PSSession @newSessionParameters -WarningVariable warning } if ($PassThru) { New-Object PSObject | Add-Member NoteProperty ExchangeWebService $script:exchangeWebService -PassThru | Add-Member NoteProperty ExchangeWebService $script:administrationSession -PassThru # | } } } $script:getExchangeItem = { param($findItem, $first, [switch]$DoNotGetDetail, [switch]$HideProgress) $foundItems = New-Object Collections.ArrayList $findItem.Item = New-Object "$namespace.IndexedPageViewType" -Property @{ MaxEntriesReturned = 120 MaxEntriesReturnedSpecified = $true } $totalItems = 0 do { if (-not $totalItems) { if (-not $hideProgress) { Write-Progress "Finding Items" "$($findItem.Item.Offset) - $($findItem.Item.Offset + $findItem.Item.MaxEntriesReturned)" -Id $getExchangeItemProgressId } } else { $percent = $findItem.Item.Offset * 100 / $totalItems if (-not $hideProgress) { Write-Progress "Finding Items" "$($findItem.Item.Offset) - $($findItem.Item.Offset + $findItem.Item.MaxEntriesReturned)" -Id $getExchangeItemProgressId -PercentComplete $percent } } $finditemresponses = $script:exchangeWebService.FindItem($findItem) $finditemresponses.ResponseMessages.Items | Where-Object {$_.ResponseClass -eq 'Error' } | ForEach-Object { Write-Error -Message $_.MessageText } $noError = $finditemresponses.ResponseMessages.Items | Where-Object { $_.ResponseCode -eq 'NoError' } $totalItems = $noError.RootFolder.TotalItemsInView $newItemIds = foreach ($ne in $noError) { foreach ($item in $ne.RootFolder.Item.Items) { if (-not $item) {continue } $item.ItemId.Id $null = $foundItems.Add(( New-Object PSObject -Property @{ Id = $item.ItemId.Id Subject= $item.Subject Item = $item })) } } if ($first -and $foundItems.Count -ge $first) { break } $findItem.Item.Offset += 120 } while ($newItemIds -and $findItem.Item.Offset -lt $totalItems) if ($DoNotGetDetail) { if ($First) { return $foundItems | Select-Object -First $first -ExpandProperty Item } else { return $foundItems | Select-Object -ExpandProperty Item } } if ($foundItems) { for ($itemNumber= 0; $itemNumber -lt $foundItems.Count;$itemNumber++) { $item = $foundItems[$itemNumber] $perc = ($itemNumber / $foundItems.count) * 100 Write-Progress "Getting Details" "$($item.Subject) " -PercentComplete $perc -Id $getExchangeItemProgressId $additionalItemsDetails = New-Object "$($script:exchangeWebService.GetType().Namespace).PathToUnindexedFieldType[]" 1 $pathToUnindexedFileType = New-Object "$($script:exchangeWebService.GetType().Namespace).PathToUnindexedFieldType" -Property @{ FieldURI = 'itemUniqueBody' -as ("$($script:exchangeWebService.GetType().Namespace).UnindexedFieldURIType" -as [type]) } $additionalItemsDetails[0] = $pathToUnindexedFileType $getItemType = New-Object "$($script:exchangeWebService.GetType().Namespace).GetItemType" -Property @{ ItemShape = New-Object "$($script:exchangeWebService.GetType().Namespace).ItemResponseShapeType" -Property @{ BaseShape = "AllProperties" AdditionalProperties = $additionalItemsDetails } ItemIds = New-Object "$($script:exchangeWebService.GetType().Namespace).ItemIdType" -Property @{Id=$item.Id} } try { $script:exchangeWebService.GetItem($getItemType) } catch { try { $script:exchangeWebService.GetItem($getItemType) } catch { Write-Error $_ } } if ($first -and ($itemNumber + 1) -ge $first) { break } } } if (-not $hideProgress) { Write-Progress "Complete" " " -Id $getExchangeItemProgressId -Completed } } $getBuriedItemDetail = { param($item, $property, $subProperty) foreach ($i in $item.$property) { if (-not $i) { continue } $i.$subProperty } } } process { if ($AsJob) { $myDefinition = [ScriptBLock]::Create("function Get-Email { $(Get-Command Get-Email | Select-Object -ExpandProperty Definition) } ") $null = $psBoundParameters.Remove('AsJob') $myJob= [ScriptBLock]::Create("" + { param([Hashtable]$parameter) } + $myDefinition + { Get-Email @parameter }) Start-Job -ScriptBlock $myJob -ArgumentList $psBoundParameters return } if (-not $exchangeServer) { $isOffice365Account = $true } if ($Credential -and ($ExchangeServer -or $IsOffice365Account)) { $connectParams = @{Account=$credential} if (-not $IsOffice365Account) { $connectParams += @{ServerName=$ExchangeServer} } else { $connectParams += @{IsOffice365Account=$IsOffice365Account} } $finalUrl = Connect-Exchange @connectParams } if (-not $script:ExchangeWebService) { #throw "Must be connected to exchange to Get-Email" #return } $namespace = $script:exchangeWebService.GetType().Namespace ## Create and Populate the Parent Folder ID Collection $parentfolderid = New-Object "$namespace.DistinguishedFolderIdType" -Property @{ Id = ("$namespace.DistinguishedFolderIdNameType" -as [Type])::Inbox } $parentFolderIds = $parentfolderid -as "$namespace.BaseFolderIdType[]" ## Create an ItemShape and set it to return All Properties $itemshape = New-Object "$namespace.ItemResponseShapeType" $itemshape.BaseShape = ("$namespace.DefaultShapeNamesType" -as [Type])::AllProperties ## Create the FindItemType object and populate with the Parent Folder Ids and Item Shape . ([ScriptBlock]::Create("[$namespace.FindItemType]`$finditemtype = New-Object `"$namespace.FindItemType`"")) $finditemtype.ParentFolderIds = $parentfolderids $finditemtype.ItemShape = $itemshape if ($SearchTerm) { $finditemtype.Restriction = New-Object "$namespace.RestrictionType" -Property @{ "Item" = New-Object "$namespace.ContainsExpressionType" -Property @{ Item = New-Object "$namespace.PathToUnindexedFieldType" -Property @{ FieldURI = ("$namespace.UnindexedFieldURIType" -as [type])::$SearchField } ContainmentModeSpecified = $true ContainmentMode = "FullString" ContainmentComparison = "LooseAndIgnoreCase" ContainmentComparisonSpecified = $true Constant = New-Object "$namespace.ConstantValueType" -Property @{ Value = "$SearchTerm" } } } } & $getExchangeItem $findItemType -first $first -DoNotGetDetail:$DoNotGetDetail | ForEach-Object { if ($_.ResponseMessages) { $item = $_.ResponseMessages.Items[0].Items.Items[0] } else { $item = $_ } $To = & $getBuriedItemDetail $item "ToRecipients", "EmailAddress" $from = & $getBuriedItemDetail $item "Sender", "EmailAddress" $cc = & $getBuriedItemDetail $item "CcRecipients", "EmailAddress" $bcc = & $getBuriedItemDetail $item "BccRecipients", "EmailAddress" if ($ExcludeThread) { $body = $item.UniqueBody.Value $BodyAsHtml = ($item.UniqueBody.BodyType1 -eq "HTML") } else { $body = $item.Body.Value $BodyAsHtml = ($item.Body.BodyType1 -eq "HTML") } $attachments = $null if ($item.hasattachments -and $DownloadAttachment) { $attachments = foreach ($attachment in $item.Attachments) { $getAttachmentType = New-Object "$($script:exchangeWebService.GetType().Namespace).GetAttachmentType" -Property @{ AttachmentShape = New-Object "$($script:exchangeWebService.GetType().Namespace).AttachmentResponseShapeType" AttachmentIds = New-Object "$($script:exchangeWebService.GetType().Namespace).RequestAttachmentIdType" -Property @{ Id = $attachment.AttachmentId.Id } } $attachmentDetails = $script:exchangeWebService.GetAttachment($getAttachmentType) $attachmentdetails.ResponseMessages.Items[0].Attachments | ForEach-Object { $path = $env:Temp + ([IO.Path]::GetRandomFileName()) + $_.Name [IO.File]::WriteAllBytes($path, $_.Content) New-Object PSObject -Property @{ Path = $path Name = $_.name } } } } if ($item) { $null = $item.pstypenames.add('Email') $item | Add-Member NoteProperty To $to -Force -PassThru | Add-Member NoteProperty Cc $cc -Force -PassThru | Add-Member NoteProperty Bcc $Bcc -Force -PassThru | Add-Member NoteProperty From $From -Force -PassThru | Add-Member Noteproperty Body $body -Force -PassThru | Add-Member Noteproperty BodyASHtml $BodyASHtml -Force -PassThru | Add-Member Noteproperty CalenderId $calenderId -Force -PassThru | Add-Member Noteproperty Attachment $attachments -Force -PassThru | Add-Member ScriptMethod GetAttachment -Force -PassThru { param([string]$Name) $getAttachmentType = New-Object "$($script:exchangeWebService.GetType().Namespace).GetAttachmentType" -Property @{ AttachmentShape = New-Object "$($script:exchangeWebService.GetType().Namespace).AttachmentResponseShapeType" AttachmentIds = New-Object "$($script:exchangeWebService.GetType().Namespace).RequestAttachmentIdType" -Property @{ Id = $attachment.AttachmentId.Id } } $attachmentDetails = $script:exchangeWebService.GetAttachment($getAttachmentType) $attachmentdetails.ResponseMessages.Items[0].Attachments | ForEach-Object { New-Object PSObject -Property @{ Name = $_.Name Bytes = $_.Content ContentType = $_.ContentType } } } } } } } |