Save Email as .MSG to Local Folder using Powershell - powershell

I have created a rule to move emails from inbox to subfolder "Task" .I am able to move the all emails from subfolder "Task" to another subfolder "Complete" in outlook but can anyone assist me in copying the emails as .msg file locally to a pre-defined folder.Below is the powershell code.
$olFolderInbox = 6;
$GetOutlook = New-Object -com "Outlook.Application";
$olName = $GetOutlook.GetNamespace("MAPI")
$olxEmailFolder = $olName.GetDefaultFolder($olFolderInbox)
$SubFolders = $olxEmailFolder.Folders | ? { $_.Name -match 'Tasks' };
$TargetFolder = $olxEmailFolder.Folders.Item('Completed')
$SubFolders.Items |
ForEach-Object -Process {
$psitem.Move($TargetFolder)
}

I am unsure if you can save an email to a .msg, however, you can save it as a .htm using the modified code
$olFolderInbox = 6
Add-Type -assembly 'Microsoft.Office.Interop.Outlook'
$GetOutlook = New-Object -ComObject 'Outlook.Application'
$olName = $GetOutlook.GetNamespace('MAPI')
$olxEmailFolder = $olName.GetDefaultFolder($olFolderInbox)
$SubFolders = $olxEmailFolder.Folders | Where-Object -FilterScript {
$_.Name -match 'Tasks'
}
$TargetFolder = $olxEmailFolder.Folders.Item('Completed')
$SubFolders.Items |
ForEach-Object -Process {
$psitem.HTMLBody | Set-Content C:\test\email.htm
$psitem.Move($TargetFolder)
}

Related

How to get powershell to attach certain file types from a directory and the latest 3 files?

I have this working partially, I can get powershell to attach the latest 3 files in this directory, but I cannot get it to only pick files based on file type or extension. My issue is that these files have no extension and are actually "files".
Can anyone help me get this script to only pick "files"
# Start-Process Outlook
$outlook = New-Object -comObject Outlook.Application
$message = $outlook.CreateItem(0)
$message.To = "test#test.com" # for multiple email use ';' as separator
#$message.CC = "" # for multiple email use ';' as separator
$message.Subject = "Files $((get-date).adddays(-1).toshortdatestring())"
$message.Body = "Attached."
$path = "C:\Downloads"
#$lastest = Get-ChildItem -Path $path -File | Sort-Object -Property LastAccessTime -Descending | Select-Object -First 3
Get-ChildItem -Path $path -File | Sort-Object -Property LastAccessTime -Descending | % { if ($_.Extension -eq ".file") {Send-Mail $_.FullName} }
foreach ($file in $lastest)
{
$message.Attachments.Add($file.FullName)
}
$message.Display()

How to fix corrupted files when download from outlook using powershell

i have a powershell script that automatically download from outlook and save in the file i already set. the script works fine but then i realise that some of the attachment downloaded is corrupted. here is the script that i use.
Function saveattachmentexcel
{
$Null = Add-type -Assembly "Microsoft.Office.Interop.Outlook"
#olFolders = "Microsoft.Office.Interop.Outlook.olDefaultFolders" -as [type]
#olFolderInbox = 6
$outlook = new-object -comobject outlook.application
$namespace = $outlook.GetNameSpace("MAPI")
$folder = $nameSpace.GetDefaultFolder([Microsoft.Office.Interop.Outlook.OlDefaultFolders]::olFolderInbox)
$filepath = "D:\DMR Folder\"
$folder.Items | Where {$_.UnRead -eq $True -and $($_.attachments).filename -match '.xlsm'} | ForEach-object {
$filename = $($_.attachments | where filename -match '.xlsm').filename
foreach($file in $filename)
{
$outpath = join-path $filepath $file
$($_.attachments).saveasfile($outpath)
}
$_.UnRead = $False
}
}
saveattachmentexcel
i do not know why this is happening. could anyone please help me?
This is likely because you attempt to save every single attachment to the same file name on disk with the $($_.attachments).saveasfile($outpath) statement.
Change this:
$filename = $($_.attachments | where filename -match '.xlsm').filename
foreach($file in $filename)
{
$outpath = join-path $filepath $file
$($_.attachments).saveasfile($outpath)
}
to:
foreach($attachment in $_.attachments)
{
if($attachment.Filename -like '*.xlsm'){
$outpath = Join-Path $filepath $attachment.Filename
# Only save this particular attachment to disk - not all of them
$attachment.SaveAsFile($outpath)
}
}

Copy multiple workbooks into a single workbooks with powershell

I am trying to copy multiple excel workbooks to a single excel workbook with the below, but it is only copying 6 columns when I have 35.
#Get a list of files to copy from
$Files = GCI 'C:\Users\bob\Desktop\Und' | ?{$_.Extension -Match "xlsx?"} | select -ExpandProperty FullName
#Launch Excel, and make it do as its told (supress confirmations)
$Excel = New-Object -ComObject Excel.Application
$Excel.Visible = $True
$Excel.DisplayAlerts = $False
#Open up a new workbook
$Dest = $Excel.Workbooks.Add()
`enter code here` ForEach($File in $Files[0..4]){
$Source = $Excel.Workbooks.Open($File,$true,$true)
If(($Dest.ActiveSheet.UsedRange.Count -eq 1) -and ([String]::IsNullOrEmpty ($Dest.ActiveSheet.Range("A1").Value2))){ #If there is only 1 used cell and it is blank select A1
[void]$source.ActiveSheet.Range("A1","F$(($Source.ActiveSheet.UsedRange.Rows|Select -Last 1).Row)").Copy()
[void]$Dest.Activate()
[void]$Dest.ActiveSheet.Range("A1").Select()}
Else{ #If there is data go to the next empty row and select Column A
[void]$source.ActiveSheet.Range("A2","F$(($Source.ActiveSheet.UsedRange.Rows|Select -Last 1).Row)").Copy()
[void]$Dest.Activate()
[void]$Dest.ActiveSheet.Range ("A$(($Dest.ActiveSheet.UsedRange.Rows|Select -last 1).row+1)").Select()}
[void]$Dest.ActiveSheet.Paste()
$Source.Close()}
$Dest.SaveAs("C:\Users\bob\Desktop\Und\combo\Combined.xlsx",51)
$Dest.close()
$Excel.Quit()
A solution with the excellent PoserShell module ImportExcel (with PowerShell 5 or more)
First, install the module:
in an Administrator PowerShell console: Install-Module -Name ImportExcel
in a non Administrator PowerShell console: Install-Module -Name ImportExcel -Scope CurrentUser
Then, use the following code:
$source = 'C:\Users\bob\Desktop\Und'
$destination = 'C:\Users\bob\Desktop\Und\combo\Combined.xlsx'
$fileList = Get-ChildItem -Path $source -Filter '*.xlsx'
foreach ($file in $fileList) {
$fileContent = Import-Excel -Path $file.FullName
$excelParameters = #{
Path = $destination
WorkSheetname = 'Combined'
}
if ((Test-Path -Path $destination) -and (Import-Excel #excelParameters)) {
$excelParameters.Append = $true
}
$fileContent | Export-Excel #excelParameters
}
This code assumes that all your Excel source files have the same headers and you want all your data in the same WorkSheet. But can be adapted to support other scenarios.

Powershell - Applying a looped function to subdirectories

I am new to Powershell and am struggling a bit. I have obtained an example of the sort of function I want to use and adapted it partially. What I want is for it to loop through each subdirectory of C:\Test\, and combine just the PDFs in each subdirectory together (leaving the resulting PDF in each subdirectory).
At the moment I can get it to comb through the subdirectories, but it then combines the contents of all subdirectories into one giant PDF in the top level directory, which is not what I want. I feel like maybe I need to use an array of sorts but I don't know Powershell well enough yet.
BTW this uses PDFSharp - a .Net library.
Function PDFCombine {
$filepath = 'C:\Test\'
$filename = '.\Combined' #<--- ???
$output = New-Object PdfSharp.Pdf.PdfDocument
$PdfReader = [PdfSharp.Pdf.IO.PdfReader]
$PdfDocumentOpenMode = [PdfSharp.Pdf.IO.PdfDocumentOpenMode]
foreach($i in (gci $filepath *.pdf -Recurse)) {
$input = New-Object PdfSharp.Pdf.PdfDocument
$input = $PdfReader::Open($i.fullname, $PdfDocumentOpenMode::Import)
$input.Pages | %{$output.AddPage($_)}
}
$output.Save($filename)
}
Your question was unclear about how many levels you need to go down. You can try this (untested). It goes one level down from $filepath, gets all pdf files in that folder and it's subfolders and combines them into Subfoldername-Combined.pdf:
Function PDFCombine {
$filepath = 'C:\Test\'
$PdfReader = [PdfSharp.Pdf.IO.PdfReader]
$PdfDocumentOpenMode = [PdfSharp.Pdf.IO.PdfDocumentOpenMode]
#Foreach subfolder(FIRST LEVEL ONLY!)
Get-ChildItem $filepath | Where-Object { $_.PSIsContainer } | Foreach-Object {
#Create new ouput pdf-file
$output = New-Object PdfSharp.Pdf.PdfDocument
$outfilepath = Join-Path $_.FullName "$($_.Name)-Combined.pdf"
#Find and add pdf files in subfolders
Get-ChildItem -Path $_.FullName -Filter *.pdf -Recurse | ForEach-Object {
#$input = New-Object PdfSharp.Pdf.PdfDocument #Don't think this one's necessary
$input = $PdfReader::Open($_.fullname, $PdfDocumentOpenMode::Import)
$input.Pages | %{ $output.AddPage($_) }
}
#Save
$output.Save($outfilepath)
}
}
So you should get this:
c:\Test\Folder1\Folder1-Combined.pdf #should include all pages in Folder1 and ANY subfolders below)
c:\Test\Folder2\Folder2-Combined.pdf #should include all pages in Folder2 and ANY subfolders below)
#etc.
If you need it to create a combined pdf for every subfolder(not only the first level), then you could try this(untested):
Function PDFCombine {
$filepath = 'C:\Test\'
$PdfReader = [PdfSharp.Pdf.IO.PdfReader]
$PdfDocumentOpenMode = [PdfSharp.Pdf.IO.PdfDocumentOpenMode]
#Foreach subfolder with pdf files
Get-ChildItem -Path $filepath -Filter *.pdf -Recurse | Group-Object DirectoryName | ForEach-Object {
#Create new ouput pdf-file
$output = New-Object PdfSharp.Pdf.PdfDocument
$outfilepath = Join-Path $_.Name "Combined.pdf"
#Find and add pdf files in subfolders
$_.Group | ForEach-Object {
#$input = New-Object PdfSharp.Pdf.PdfDocument #I don't think you need this
$input = $PdfReader::Open($_.fullname, $PdfDocumentOpenMode::Import)
$input.Pages | %{ $output.AddPage($_) }
}
#Save
$output.Save($outfilepath)
#Remove output-object
Remove-Variable output
}
}
not tested ...
Function PDFCombine {
$filepath = 'C:\Test\'
$filename = '.\Combined' #<--- ???
$output = New-Object PdfSharp.Pdf.PdfDocument
$PdfReader = [PdfSharp.Pdf.IO.PdfReader]
$PdfDocumentOpenMode = [PdfSharp.Pdf.IO.PdfDocumentOpenMode]
$lastdir=""
foreach($i in (gci $filepath *.pdf -Recurse)) {
$input = New-Object PdfSharp.Pdf.PdfDocument
$input = $PdfReader::Open($i.fullname, $PdfDocumentOpenMode::Import)
$input.Pages | %{$output.AddPage($_)}
if ($lastdir -ne $_.directoryname){
$lastdir=$_.directoryname
$output.Save("$lastdir\$filename")
$output = New-Object PdfSharp.Pdf.PdfDocument
}
}
}

How to specify a subfolder of Inbox using Powershell

I'm trying to access a subfolder of "Inbox" named "subfolder" in outlook (2010) using Powershell.
$olFolderInbox = 6
$outlook = new-object -com outlook.application;
$ns = $outlook.GetNameSpace("MAPI");
$inbox = $ns.GetDefaultFolder($olFolderInbox)
# how do I specify a subfolder that's inside Inbox???
# I mean, "Inbox\subfolder" where "subfolder" is the name of the subfolder...
How do I specify this subfolder?
I'm sure this is really simple, which is why I am about to "lose it." Thanks in advance!
*Later in my code,
I search the body for a "searchterm" and send the results to a text file if there's a match. The following code works for my Inbox:
$inbox.items | foreach {
if($_.body -match "searchterm") {$_.body | out-file -encoding ASCII foo.txt} # prints to file...
Instead of the inbox, I want to look at the subfolder of inbox as described above...
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT:
$olFolderInbox = 6
$outlook = new-object -com outlook.application;
$ns = $outlook.GetNameSpace("MAPI");
$inbox = $ns.GetDefaultFolder($olFolderInbox)
$targetfolder = $inbox.Folders | where-object { $_.name -eq "Subfolder" }
$targetfolder.items | foreach {
if($_.body -match "keyword") {$_.body | out-file -Append -encoding ASCII foo.txt} # keyword match prints body to file...
}
OK, I think this works now...
I don't know what I was doing wrong, although it's literally my first day using Powershell, so it's no surprise, really.
$targetfolder = $inbox.Folders | where-object { $_.name -eq "subfolder" }
$targetfolder.items | where-object { $_.body -match "keyword" } | % { $_.body } # can then redirect the body to file etc.
EDIT: not sure why your newest edit wouldn't work. Yours looks to be similar in construction to the one I have above, which I verified against my own mailbox.
EDIT EDIT: Be sure that if you're using out-file, you append the results rather than overwriting with each match.
Try using the Where-Object cmdlet to filter the Folders returned from $inbox.Folders.
$Subfolder = $inbox.Folders | Where-Object -FilterScript { (Split-Path -Path $_.FolderPath -Leaf) -eq 'Subfolder' }
Here is an alternative / short-hand version of the above. This won't be quite as reliable, since you could have another folder called MySubfolder that's distinct from Subfolder.
$Subfolder = $inbox.Folders | ? { $_.FolderPath.EndsWith('Subfolder') }