I am trying to move emails within outlook from one folder to another.
However, my code throws an error on processing of the last email.
"Unable to index into an object of type System.__ComObject."
it moves all other emails to the archive folder ok.
If only 1 email present, it will error....
If 2 or more emails present then it will move all but the last email and then error.
Code is
$filepath="Z:\"
$olFolderInbox = 6
$i=0
$outlook = new-object -com outlook.application;
$ns = $outlook.GetNameSpace("MAPI");
$inbox = $ns.Folders | ? { $_.Name -eq '#Whe ContractorRFPs' };
$trgtfldr = $inbox.Folders | ? { $_.Name -match 'Inbox' };
$mvdfldr = $inbox.Folders | ? { $_.Name -match 'Archived' };
$messages = $trgtfldr.items
for($i=($messages.count -1);$i -gt -1;$i--){
$($messages)[$i].move($mvdfldr)
}
You could set up your loop like this
$messages = $trgtfldr.items
$messageCount = $messages.count
for ($i = $messageCount - 1; $i -ge 0; $i--) {
$message = $messages.GetLast()
$message.move($mvdfldr)
}
Why not use a foreach loop?
$messages = $trgtfldr.items
foreach($message in $messages){
$message.move($mvdfldr)
}
Related
I would like to modify the script below, to send the email with embedded text, without removing the html attachments.
The data it should embed into the email is found at: "C:\Users\Users\Summary\SummaryCSV.txt"
Here is the Powershell Script which needs to be modified:
# Check to see we have all the arguments
If (Test-Path -Path "C:\Users\Users\Summary\SummaryCSV.txt") {
#Send Email with HTML as attachment and no text embedded
$FullPath=$args[0]
#Get an Outlook application object
$o = New-Object -com Outlook.Application
$mail = $o.CreateItem(0)
#2 = High importance message
$mail.importance = 1
$mail.subject = "Ready to be retrieved: $(get-date)"
$mail.body = "Summary $(get-date)"
#separate multiple recipients with a ";"
$mail.To = "email#email1.com"
# Iterate over all files and only add the ones that have an .html extension
$files = Get-ChildItem $FullPath
for ($i=0; $i -lt $files.Count; $i++) {
$outfileName = $files[$i].FullName
$outfileNameExtension = $files[$i].Extension
# if the extension is the one we want, add to attachments
if($outfileNameExtension -eq ".html")
{
$mail.Attachments.Add($outfileName);
}
}
$mail.Send()
# give time to send the email
Start-Sleep 5
# quit Outlook
$o.Quit()
#end the script
#exit
}
Thanks in advance for your assistance.
Based on your specifications:
# Check to see we have all the arguments
If ((Test-Path -Path C:\Users\Users\Summary\SummaryCSV.txt) -and (Test-Path -Path C:\Users\Users\Summary\SummaryCSV.txt)) {
#Send Email with HTML as attachment and no text embedded
$FullPath=$args[0]
$embeddedText = Get-Content -Path C:\Users\Users\Summary\SummaryCSV.txt -Raw
#Get an Outlook application object
$o = New-Object -com Outlook.Application
$mail = $o.CreateItem(0)
#2 = High importance message
$mail.importance = 1
$mail.subject = "Ready to be retrieved: $(get-date)"
$mail.body = "Summary $(get-date)`r`n$embeddedText"
#separate multiple recipients with a ";"
$mail.To = "email#email1.com"
# Iterate over all files and only add the ones that have an .html extension
$files = Get-ChildItem $FullPath
for ($i=0; $i -lt $files.Count; $i++) {
$outfileName = $files[$i].FullName
$outfileNameExtension = $files[$i].Extension
# if the extension is the one we want, add to attachments
if($outfileNameExtension -eq ".html") {
$mail.Attachments.Add($outfileName);
}
}
$mail.Send()
# give time to send the email
Start-Sleep 5
# quit Outlook
$o.Quit()
#end the script
#exit
}
I have a powershell script which downloads outlook mail attachments.
But I recieve below error:
Method invocation failed because [System.String] does not contain a method named 'saveasfile'.
I have used below script
Add-Type -Assembly "Microsoft.Office.Interop.Outlook"
$Outlook = New-Object -ComObject Outlook.Application
$Namespace = $Outlook.GetNameSpace("MAPI")
$inbox = $mapi.GetDefaultFolder(6)
$saveFilePath = "C:\temp\"
$subfolder = $inbox.Folders | Where-Object {$_.Name -eq “REPORTS”}
$mail = $subfolder.Items | Select-Object -Property Subject,SentOn,#{name="Attachments";expression={$_.Attachments|%{$_.DisplayName}}} | Where-Object{$_.attachments -match ".html" -and ($_.SentOn -gt '29-Oct-19 12:00:00 AM')}
foreach ($email in $mail)
{
if ($email.attachments.count -ge 1)
{
foreach ($attachment in $email.attachments)
{
$filename = $attachment.filename
$attachment.saveasfile((join-path $savefilepath $filename))
}
}
}
Please let me know how can I resolve this error.
Outlook's Attachments property's enumerator returns a String key, not an actual attachment object (this is why using an untyped or weakly-typed language like PowerShell for working with COM is a very bad idea).
While PowerShell wants to be used as a functional, pipelining language (which is a PITA to debug) - sometimes it's easier to use old-fashioned imperative code:
For( $i = 0; $i -le $email.Attachments.Count; $i++ ) {
$attachment = $email.Attachments.Item( $i )
$attachment.SaveAsFile( ( Join-Path $savefilepath $filename ) )
}
BTW, you don't need the if ($email.attachments.count -ge 1) statement because the For( $i = 0; $i... loop also checks the .Attachments.Count property too.
I want to replace text in FieldCodes (Word Document). How can i use variables for that?
This is for a Word Doc with links to other Word Doc's (IncludeText Link). When i change the link one by one without variable it works. When i use variables for it, it doesn't.
$Desktop = [Environment]::GetFolderPath("Desktop")
$Word = New-Object -ComObject Word.Application
$Document = $Word.Documents.Open("$Desktop\Test.docx")
$Test = 147 # (Test.GetType() = Int32)
$Document.Fields(147) #Works
$Document.Fields($Test) #Works
$Document.Fields($Test).LinkFormat.SourceFullName = "" #Works
$TextLinks = $Document.Fields | Where-Object Type -eq "68" | Select -expand Index
#TextLinks contains value 147 and 149
$Test = $TextLinks[0] # is also 147 (Test.GetType() = Int32)
$Document.Fields($Test) #Doesn't work (runs indefinitely)
$Document.Fields($Test).LinkFormat.SourceFullName = "" #Doesn't work (runs indefinitely)
147..149 | Foreach { $Document.Fields($_).LinkFormat.SourceFullName } #Doesn't work (runs indefinitely)
Update:
Now it runs with $Test = [INT]$Textlinks[0]. Thanks Cindy!
But when i try a loop it hangs with te second value
$Desktop = [Environment]::GetFolderPath("Desktop")
$Word = New-Object -ComObject Word.Application
$Document = $Word.Documents.Open("$Desktop\Test.docx")
$TextLinks = $Document.Fields | Where-Object Type -eq "68" | Select -expand Index
$ItemNumber = 0
$End = $TextLinks.Count
Do {
$Item = [INT]$Textlinks[$ItemNumber]
if ($Document.Fields($Item).LinkFormat.SourceFullName -match "Test") {
$Link = $Document.Fields($Item).LinkFormat.SourceFullName -replace "Test", "TestTest"
$Document.Fields($Item).LinkFormat.SourceFullName = $Link
$Document.Fields($Item).LinkFormat.AutoUpdate = "True"
$ItemNumber += 1
}
} Until ($ItemNumber -eq $End)
$Document.Save()
$Word.Quit()
$OUT=[System.Runtime.InteropServices.Marshal]::ReleaseComObject($Word)
Update 2:
Code below runs fine but i dont understand why the code above doesn't
$Desktop = [Environment]::GetFolderPath("Desktop")
$Word = New-Object -ComObject Word.Application
$Document = $Word.Documents.Open("$Desktop\Test.docx")
$TextLinks = $Document.Fields | Where-Object Type -eq "68" | Select -expand Index
$ItemNumber = ($TextLinks.Count)-1
$End = -1
Do {
$Item = [INT]$Textlinks[$ItemNumber]
if ($Document.Fields($Item).LinkFormat.SourceFullName -match "Test") {
$Link = $Document.Fields($Item).LinkFormat.SourceFullName -replace "Test", "TestTest"
$Document.Fields($Item).LinkFormat.SourceFullName = $Link
$Document.Fields($Item).LinkFormat.AutoUpdate = "True"
$ItemNumber -= 1
}
} Until ($ItemNumber -eq $End)
$Document.Save()
$Word.Quit()
$OUT=[System.Runtime.InteropServices.Marshal]::ReleaseComObject($Word)
I have a script that is supposed to download all attachments from "Inbox" then move them to another folder named "Processed". I filter mails by subject. If exist then download all attachments and move the mails.
For example I have 5 mails with attachments (xls) the subject are named like:
BB_asd_green_dsa
AD_acv_blue_sf
FD__c_d_red_sa
CV_saas_white_sdsd
as_dc_asa_purple
When I start the script it saves 3 attachments, the mails with attachments are moved too. And then it stops.
Second start. It saves 1 attachment & moves 1 mail
And one last manual start script saves the last attachment and moves the mail.
For what reason doesn't the script save and move all attachments with their mails?
Here is the script:
$olFolderInbox = 6
$outlook = New-Object -Com Outlook.Application;
$ns = $outlook.GetNameSpace("MAPI");
#$ns.Logon("Outlook")
#$ns.SendAndReceive($true)
#Start-Sleep -s 0
$inbox = $ns.GetDefaultFolder($olFolderInbox)
$messages = $inbox.Items
Write-Host $messages.Count
foreach ($message in $messages) {
$msubject = $message.Subject
$b = $msubject.Filename
$filepath = "D:\Users\h.yordanov\Desktop\convertexltohtm\xls\"
$message.Attachments | foreach{
Write-Host $message.Filename
$a = $_.Filename
$msubject = $message.Subject
$msubjectW = $msubject -replace '[^0-9]', ''
$b = $msubjectW + ".xls"
if ($msubject.Contains("green") -or $msubject.Contains("blue") -or $msubject.Contains("green") -or $msubject.Contains("white") -or $msubject.Contains("purple")) {
$_.SaveAsFile((Join-Path $filepath $b))
}
}
$MoveTarget = $inbox.Folders.Item("Processed")
[void]$message.Move($MoveTarget)
}
I used this script to move the mails, but still not all 5 mails are moved at once:
$Date = [DateTime]::Now.AddDays(-180)
$Last6Months = $Date.tostring("MM/dd/yyyy")
$o = New-Object -comobject outlook.application
$n = $o.GetNamespace(“MAPI”)
$Account = $n.Folders | ? { $_.Name -eq 'h.yordanov#sample.com' };
$Inbox = $Account.Folders | ? { $_.Name -match 'Inbox' };
$TargetFolder = $Inbox.Folders.Item('Processed')
$Inbox.Items |
Where-Object -FilterScript {
$_.senton -ge "$Last6Months"
} |
ForEach-Object -Process {
[void]$psitem.Move($TargetFolder)
}
Btw i am using MS office Pro plus 2010 64-bit
Currently, I'm trying to get attachment names from E-Mails within a PST-File. I want to do this via Powershell. My code bracket works fine so far, except for one thing. It Just writes System.__ComObject as the attachments name. Any ideas?
## Path where the PSTFiles are
$PSTArr = Get-ChildItem -Path .\ -Recurse
$Attachments = #()
## Processing
ForEach ($PST in $PSTArr) {
if ($PST.Name -like "*.pst") {
[string]$pstPath = $PST.FullName
Write-Output ("Checking File: " + $pstPath)
# Lets see if there is a running outlook process
$oProc = ( Get-Process | where { $_.Name -eq "OUTLOOK" } )
if ( $oProc -eq $null ) { Start-Process outlook -WindowStyle Hidden; Start-Sleep -Seconds 5 }
$outlook = New-Object -ComObject Outlook.Application
# Assign namespace
$namespace = $outlook.GetNamespace("MAPI")
# Add PST
$namespace.AddStore($pstPath)
$pstStore = ( $nameSpace.Stores | where { $_.FilePath -eq $pstPath } )
# Add RootFolder of the PST
$pstRootFolder = $pstStore.GetRootFolder()
# Get attachments of the E-Mails
$Attachments += $pstRootFolder.Items | Select Attachment
# Disconnect PST File
$namespace.GetType().InvokeMember('RemoveStore',[System.Reflection.BindingFlags]::InvokeMethod,$null,$namespace,($pstRootFolder))
}
}
(I'm looping through a Folder with PST's, which works fine)
Thanks for help / answers
Try this:
$Attachments = $pstRootFolder.Items | ForEach-Object {
$_.Attachments | Select-Object -ExpandProperty FileName
}