I have an email that comes in daily to a gmail hosted email. Normally I have no problem downloading through a script, however, this time the filename coming as an attachment has colons ( in it. The subject of the email is always the same, so its easy to identify the email and find the attachment, but given my current code, it says the path is not supported and I am at a loss. My current code is:
# !=========== DownloadReports (Date; dd-MMM-yyyy) ==============!
# This function downloads the reports that are attachments on emails sent from the system
Function DownloadReports-All ($date) {
# Load IMAPX module
$dll = "$dir\ImapX.dll"
[Reflection.Assembly]::LoadFile($dll)
# Setup Credentials
$pwdgmail = ConvertTo-SecureString "gmailpassword" -AsPlainText -Force
$bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($pwdgmail)
$Username = "emailaddress"
$Password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
# Initialize the IMAP client
$client = New-Object ImapX.ImapClient
# Set Fetching Mode to retrieve the part of message needed (less is better)
$client.Behavior.MessageFetchMode = "Full"
$client.Host = "imap.gmail.com"
$client.Port = 993
$client.UseSsl = $true
$client.Connect()
$client.Login($Username,$Password)
# Get folder/label object containing emails you want to read from
$res = $client.folders.subfolders | where { $_.path -eq '[Gmail]/All Mail'}
# Create search query
$searchSinceDate = $date
$searchQuery = 'SUBJECT "Subject I am searching for" SINCE ' + $searchSinceDate + ''
Write-Host "Searching Emails for: $searchQuery"
# Search email threads inside the subfolder
$numberOfMessagesLimit = 200
$messages = $res.search($searchQuery, $client.Behavior.MessageFetchMode, $numberOfMessagesLimit)
# Create Attachment Folder
New-Item $dir\Attachments -ItemType Directory -Force
# Set Folder Path for Attachments
$folderPath = Resolve-Path -Path "$dir\Attachments\"
# for each message, download attachment if it exists
# download into its own folder
$counter = 0
$messageCount = 0
foreach ($message in $messages) {
Write-Host "Processing the next message: $message"
foreach ($i in $message.Attachments) {
Write-Host "Processing the next attachment: $i"
# Reset SubFolder location
$strCounter = [string]$counter
$subfolderPath = $dir + "\Attachments\Attachment_" + $strCounter
# Reset SubFolder location
$strCounter = [string]$counter
$subfolderPath = $dir + "\Attachments\Attachment_" + $strCounter
# Create new sub-folder
New-Item $subfolderPath -ItemType Directory -Force
$subfolderPath = Resolve-Path -Path $subfolderPath
# Fetch emails
$i.Download();
foreach($i in $messages.Attachments) {
if($i -ne $null) {
$i.Download()
$filename = $attachment.FileName
$illegalChars = [System.IO.Path]::GetInvalidFileNameChars()
foreach ($char in $illegalChars) {
if ($filename -ne $null) {
$filename = $filename.Replace($char, '_')
}
# Download attachments to location
$i.Save($subfolderPath)
# Uptick counter
$counter++
Write-Host "Finished with this attachment: $i"
Write-Host "Counter is now $counter"
}
Write-Host "Finished with this message: $message"
}
# Display the messages in a formatted table
$messages | ft *
$client.Disconnect()
}
}}}
# ========== Initialization ============
$dir = "$PSScriptRoot"
$inputFileName = "sampleCSV.csv"
$outputFileName = "SampleHTML_built-in2.html"
$title = "Sample Output HTML from CSV"
# Get current date
#$currentDate = Get-Date -Format "dd-MMM-yyyy"
$currentDate = (Get-Date).AddDays(0)
$currentDate = $currentDate.ToString("dd-MMM-yyyy")
# - Path initialization
$inputFilePath = "$dir\$inputFileName"
$outputFilePath = "$dir\$outputFileName"
# ============ Main Program ===============
# ----- Clean Up Last Day's Run-----
Remove-Item -Recurse -Force "$dir\Attachments\"
# ----- Retrieve Attachments for current day ------
DownloadReports-All($currentDate)
# ----- Get List of Files to Process (Should only be one) -----
$files = Get-ChildItem $dir\Attachments -Filter *.* -Recurse
The error I am getting is:
Counter is now 35
Exception calling “Save” with “1” argument(s): “The given path’s format is not supported.”
At D:\autoloader\Plains_TT\PlainsTTEmailRetrieval.ps1:81 char:3
If you check the array returned by GetInvalidFileNameChars() you’ll see it doesn’t contain the : character - at least it doesn’t on my system. Checking the docs:
The array returned from this method is not guaranteed to contain the complete set of characters that are invalid in file and directory names.
Add another replace() or -replace to replace the : with a replacement character.
Makes sense! I did do a replacement with -replace however I still get the same error listed below the following amended script.
# !=========== DownloadReports (Date; dd-MMM-yyyy) ==============!
# This function downloads the reports that are attachments on emails sent from the system
Function DownloadReports-All ($date) {
# Load IMAPX module
$dll = "$dir\ImapX.dll"
[Reflection.Assembly]::LoadFile($dll)
# Setup Credentials
$pwdgmail = ConvertTo-SecureString "automation7878" -AsPlainText -Force
$bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($pwdgmail)
$Username = "dsautomation@datascavenger.com"
$Password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
# Initialize the IMAP client
$client = New-Object ImapX.ImapClient
# Set Fetching Mode to retrieve the part of message needed (less is better)
$client.Behavior.MessageFetchMode = "Full"
$client.Host = "imap.gmail.com"
$client.Port = 993
$client.UseSsl = $true
$client.Connect()
$client.Login($Username,$Password)
# Get folder/label object containing emails you want to read from
$res = $client.folders.subfolders | where { $_.path -eq '[Gmail]/All Mail'}
# Create search query
$searchSinceDate = $date
$searchQuery = 'SUBJECT "#44 Plains Midstream Customer Report - 100/04-13-039-09W5 Orlen" SINCE ' + $searchSinceDate + ''
Write-Host "Searching Emails for: $searchQuery"
# Search email threads inside the subfolder
$numberOfMessagesLimit = 200
$messages = $res.search($searchQuery, $client.Behavior.MessageFetchMode, $numberOfMessagesLimit)
# Create Attachment Folder
New-Item $dir\Attachments -ItemType Directory -Force
# Set Folder Path for Attachments
$folderPath = Resolve-Path -Path "$dir\Attachments\"
# for each message, download attachment if it exists
# download into its own folder
$counter = 0
$messageCount = 0
foreach ($message in $messages) {
Write-Host "Processing the next message: $message"
foreach ($i in $message.Attachments) {
Write-Host "Processing the next attachment: $i"
# Reset SubFolder location
$strCounter = [string]$counter
$subfolderPath = $dir + "\Attachments\Attachment_" + $strCounter
# Reset SubFolder location
$strCounter = [string]$counter
$subfolderPath = $dir + "\Attachments\Attachment_" + $strCounter
# Create new sub-folder
New-Item $subfolderPath -ItemType Directory -Force
$subfolderPath = Resolve-Path -Path $subfolderPath
# Fetch emails
$i.Download();
foreach($i in $messages.Attachments) {
if($i -ne $null) {
$i.Download()
$filename = $attachment.FileName
$filename.Replace(':','')
# Download attachments to location
$i.Save($subfolderPath)
# Uptick counter
$counter++
Write-Host "Finished with this attachment: $i"
Write-Host "Counter is now $counter"
}
Write-Host "Finished with this message: $message"
}
# Display the messages in a formatted table
$messages | ft *
$client.Disconnect()
}
}}
Exception calling “Save” with “1” argument(s): “The given path’s format is not supported.”
At D:\autoloader\Plains_TT\PlainsTTEmailRetrieval.ps1:76 char:3
OK, that looks like a PathInfo object. Ignore my previous edit for now.
It looks like this $subfolderPath = $dir + "\Attachments\Attachment_" + $strCounter
which should be a string, is being overwritten by this: $subfolderPath = Resolve-Path -Path $subfolderPath
which returns a PathInfo object.
And this $i.Save($subfolderPath)
can’t pull the Path property from the PathInfo object.
Exception calling “Save” with “1” argument(s): “The given path’s format is not supported.”
At D:\autoloader\Plains_TT\PlainsTTEmailRetrieval.ps1:76 char:3
I’m pretty sure $dir is an alias for the existing directory that the script is running from which is my designated starting point for the attachments folders. Everything else works up until the actual save of the file to the subfolderpath. All write-output’s show a valid filename and path however it still says file path is not valid.
I also just tried $i.Save(“$subfolderPath.Path$attachmentName”) with and without the .Path after the $subfolderPath and it gave the same error both times. Is it potentially defaulting back to the original file name with the special characters in it because of $attachmentName. Is there a way of defining the filename after the special characters have been removed and using that in the save path?
Yes, I think it’s not updating the filename - it may be a read only property, or it might be you’re not reassigning it.
Unfortunately, I cannot test it because you can’t override Google’s security settings to use PowerShell to connect to mailbox unless you’re using Workspaces.
Is filename a property of $i?
Can you confirm that the script works OK, as originally provided, when the attachment does not contain colons.
I would like to let you know that you are smarter than AI! I tried troubleshooting it with ChatGPT, but it didn’t work. Went through it for 2 days straight with no resolution before coming here. I am so glad I came here! THANK YOU!!!