Parse .msg files to fetch To, from, subject and date using Powershell - powershell

I am trying to get To, From, subject, sent date from about a 100 .msg files that are saved in a folder on my local drive, possibly get all that info in a csv using powershell.
I ran this code I got from another post
Get-ChildItem "C:\--------\msgfileshere" -Filter *.msg |
ForEach-Object{
$outlook = New-Object -comobject outlook.application
$msg = $outlook.CreateItemFromTemplate($_.FullName)
$msg | Select From,to,subject,Senton,Cc|ft -AutoSize
}
I am able to get Subject and Senton date.
But no other information comes out related to Sender, to, Cc. Am I missing something here?
Edit: I was able to get Sender info which gives System.__ComObject as the output but not the actual email address

Related

How to download first emails attachment using PowerShell?

I'm getting an automatic weekly email with an attachment, and with an outlook rule, it is being saved in a folder in my inbox. my goal is to create a PowerShell script that downloads the attachment from the email with the latest "ReceivedTime". I have managed to sort the Object in the folder by "ReceivedTime" and get the latest email in the list: "$emails[0]", I can see the name of the attachment but I cannot seem to find how to download the file itself.
the error I get is as follows: "You cannot call a method on a null-valued expression."
my code look like this:
$outlook = New-Object -ComObject outlook.application
$mapi = $outlook.GetNamespace("MAPI");
#Get Folder path
$filePath = "C:\Temp\test"
$inbox = $mapi.GetDefaultFolder(6)
$inbox.Folders | Select-Object FolderPath
$olFolderPath = "\\DanielMol#sodastream.com\Inbox\compliance"
#Get Emails Items from folder
$targetFolder = $inbox.Folders | Where-Object { $_.FolderPath -eq $olFolderPath }
#Sort Emails in folder by date
$emails = $targetFolder.Items | Sort-Object ReceivedTime -Descending
#download attachements
$emails[0].Attachments | Select-Object $_.saveasfile(($filePath))
I'm using this guide to download the attachment, but my use case is a bit different from what is described in the article: https://bronowski.it/blog/2020/09/saving-outlook-attachments-with-powershell/
Sorry if it is a very simple task, I'm new to PowerShell and just learning automation.
Thank you very much :)
First of all, I've noticed the following code:
#Sort Emails in folder by date
$emails = $targetFolder.Items | Sort-Object ReceivedTime -Descending
Instead, you need to use the Sort method of the Items class which sorts the collection of items by the specified property. The index for the collection is reset to 1 upon completion of this method. So, to get the first item use the 1 index instead of 0.
$emails[1].Attachments[1].SaveAsFile(($filePath))
Be aware, the Attachments object contains a set of Attachment objects that represent the attachments in an Outlook item. Use the Attachments property to return the Attachments collection for any Outlook item (except notes).

Marking Emails as Read

I might be asking this in the wrong place so I apologize. I'm running a PS1 file to look in a specific folder, mark the emails as read, save the attachments and send me an email. For whatever reason, marking the emails as read, doesn't always work.
Since everything else works perfectly, I'll leave you with just what is not working
#Open Outlook and find emails from today
$ol = New-Object -ComObject Outlook.Application
$ns = $ol.GetNamespace('mapi')
$mb = $ns.Stores['some#email.com'].GetRootFolder()
$inbox = $mb.Folders['Reports']
$inbox.Items | ForEach-Object {$_.UnRead = $false}
If I run the script in ISE one line at a time, it works.
The problem arises when I select all and run in ISE, or as a PS1
Thanks!

Who to email based on attachment file

Without using a ton of ElseIf statements is it possible to select the the recipient of an email based on the file that will be attached to the email while iterating over all files in a folder?
I have started building this without the foreach get-ChildItem running over the folder where I create the email object, assign specific recipients, and choose a specific file out of the folder, but this is quite tedious and repetitive. I feel like there has to be a way to use an array of arrays or something where based on the file that the loop is on it pulls through the recipients and maybe a custom subject line.
There's tons of powershell email code out there so I won't repost that. Just not sure how to even attack this.
One option would be to have an accompanying CSV file, with rows for the filename, the recipient and the subject name etc. You could then import the CSV file using Import-Csv.
For example:
$emailList = Import-csv c:\users.csv
foreach ($line in $emailList) {
Write-Host "Sending message to $($line.emailAddress)"
Send-MailMessage -To $line.emailAddress `
-Subject $line.subject `
-Attachments $line.attachmentPath `
-Body $line.bodyText
}
and if you wanted to define the contents of the CSV in the PowerShell script, rather than using an external file, you could do something like:
$emailList = "emailAddress,subject,attachmentPath,bodyText
joe#bloggs.com,Attachment for Joe,c:\attachmentsToSend\joe.pdf,Attached is your file
Mary#bloggs.com,Mary's attachment,c:\attachmentsToSend\mary.pdf,Hello, Mary. Attached is your file
" | ConvertFrom-Csv
Put that above the foreach loop in the script

Powershell ews script to read mail from my mailbox is retrieving values for FROM and SUBJECT but is not returning anything for mail body

I have written a powershell script to return the FROM, SUBJECT and mail body from the latest mail from my outlook exchange mailbox. The script is returning the FROM and SUBJECT but nothing for the mail body. Below is my code snippet
$findResults=$inbox.FindItems(1)
foreach ($item in $findResults.Items)
{
"From: $($item.From.Name)"
"Subject: $($item.Subject)"
"Body: $($Item.Body.Text)"
$item.From.Name| Out-File 'D:\newsample.txt'
$item.Subject| Out-File 'D:\newsample.txt' -Append
$item.Body.Text| Out-File 'D:\newsample.txt' -Append
}
There is no output for mail body in console nor in file.
Please help me out in sorting out the problem
Create a PropertySet to access the Body property, as it's not available from the FindItems call.
$psPropertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
$psPropertySet.RequestedBodyType = [Microsoft.Exchange.WebServices.Data.BodyType]::Text;
and then load the PropertySet to get the Body
$item.load($psPropertySet)

Powershell novice looking to create script to trigger notifications on missing files

Long time lurker first time poster. I'm looking(of my own initiative) to see if there is a method by which I can check for missing files, that we would expect to receive on a daily basis, and be notified via e-mail.
Our company has what I'd call a relatively unhinged systems infrstructure, that since I arrived I've been chipping away here and there putting in some practices and process' to be more proactive with our monitoring.
Specifically in this case, we receive files via FTP from a vendor, that outlines our Sales and other data. These files go through some validation and the data is then imported into our ERP platform. However I am interested to put in a check, that raises and alert when a file has not been received, when expected.
The last part of that requirement can potentially change, I'm not sure how specific I can get when trying to raise an alert from an expected file.
I'll outline this by stating I'm a relative novice in this area, but there is really no one in my department any the wiser. So I've been looking into powershell.
I've created the following two bits of codes so far, that when executed appear to return files that have been created/last writ, within the last day. This would even be enough, to have this output sent via e-mail. I would be able to spot quickly if an expected file is not in the list.
GET-ChildItem -Path "Path I am checking" |
Where-Object {$_.LastWritetime -gt (get-Date).AddDays(-1)}
The above returns one .csv file. I guess if I get a returned file, then I know its been provided, and if the return is blank/zero, then I know I didn't get a file.
I've used the above for four seperate checks, checking other subfolders in the structure.
To outline the folder structure
\"App server"\"Region"\"Vendor"
There are then the following subfolders
Purchases
Sales
Tenders
VAT
Each of the above four folders then has
Incoming
Processed
I am running my checks on the processed folder for each of the four folder outlined above.
Maybe something like this will help you out:
Function Test-NewerFiles {
# We use parameters as it makes things easy when we need to change things
# CmdLetBinding makes sure that we can see our 'Write-Verbose' messages if we want to
[CmdLetBinding()]
Param (
[String]$Path = 'C:\Users\me\Downloads\Input_Test',
[String]$ExportFile = 'C:\Users\me\Downloads\Log_Test\Attachment.txt'
)
# We first save the date, then we don't need to do this every time again
$CompareDate = (Get-Date).AddDays(-1)
# Then we collect only the folders and check each folder for files and count them
Get-ChildItem -Path $Path -Directory -Recurse | ForEach-Object {
$Files = (Get-ChildItem -Path $_.FullName -File | Where-Object {$_.LastWritetime -gt $CompareDate} | Measure-Object).Count
# If we didn't find files the count is 0 and we report this
if ($Files -eq 0) {
Write-Verbose "No files found in folder $($_.FullName)"
Write-Output $_.FullName
}
# If we found files it's ok and we don't report it
else {
Write-Verbose "Files found in folder $($_.FullName)"
}
}
}
# If you don't want to see output you can remove the '-Verbose' switch
Test-NewerFiles -Verbose
$MyNewFiles = Test-NewerFiles
$MyNewFiles | Out-File -FilePath $ExportFile -Encoding utf8
if ($MyNewFiles) {
$MailParams = #{
To = 'Chuck.Norris#world.com'
From = 'MyScriptServer#world.com'
SmtpServer = 'SMTPServer'
}
Send-MailMessage #MailParams -Priority High -Attachments $ExportFile -Body 'We found problems: check attachment for details'
}
else {
Send-MailMessage #MailParams -Priority Low -Body 'All is ok'
}
The Verbose switch is only used to report progress. So we can see what it does when it's running. But when we use this code in production, we don't need these messages and just use Test-NewerFiles instead of Test-NewerFiles -Verbose.