PowerShell code to send files in each sub-folder as email attachments - powershell

I'm trying to write a PowerShell script that would email as attachments, all files in each subfolder of C:\Reports\ together. For instance, if the subfolders are C:\Reports\ABC having a.txt, b.xml and c.jpg and C:\Reports\DEF having d.txt, e.xml and f.pdf, the code should email a.txt, b.xml and c.jpg in one email and d.txt, e.xml and f.pdf in another.
#Connection Details
$username = ”vallabhherlekar#gmail.com”
$password = ”Appya1979!”
$smtpServer = “smtp.gmail.com”
$Directory = Get-ChildItem “C:\Reports\” -Directory
foreach ($d in $Directory) {
$msg = New-Object Net.Mail.MailMessage
$smtp = New-Object Net.Mail.SmtpClient($SmtpServer, 587)
#Uncomment Next line for SSL
$smtp.EnableSsl = $true
$smtp.Credentials = New-Object System.Net.NetworkCredential ($username, $password)
$msg.From = "vallabhherlekar#gmail.com"
$msg.To.Add(“vallabhherlekar#gmail.com”)
$msg.Body=”Please See Attached Files”
$msg.Subject = “Email with Multiple Attachments”
Write-Host "Working on directory $($d.FullName)..."
$files = Get-ChildItem -Path "$($d.FullName)" -File
foreach ($file in $files) {
Write-Host “Attaching File :- ” $file.FullName
$attachment = New-Object System.Net.Mail.Attachment –ArgumentList
$file.FullName
$msg.Attachments.Add($attachment)
}
$smtp.Send($msg)
$attachment.Dispose();
$msg.Dispose();
}

Related

Powershell to monitor a folder and send email when there are new files

I need some assistance on how to create a powershell to monitor a folder and subfolders and send an email every 15 minutes for example, with a list of files that added to this folder
I will set up a schedule task to run every 15 minutes
Email output will be something like:
File Name, Path
TEST.TXT uploaded to C:\ROOT\BUSINESS
test2.txt uploaded to C:\ROOT\BUSINESS\May2021
Here is what I have so far. Any help is appreciated.
SMTPServer = "EMAIL SERVER (ip)"
$SMTPPort = "111"
$Username = "SENDER#EMAIL.COM"
$path="C:\ROOT\BUSINESS\"
$to = "test1#gmail.com"
$cc = "test2#gmail.com"
$subject = " New File available "
$message = New-Object System.Net.Mail.MailMessage
$message.subject = $subject
$message.to.add($to)
$message.cc.add($cc)
$message.from = $username
$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);
$smtp.EnableSSL = $true
#$smtp.Credentials = New-Object System.Net.NetworkCredential $Username;
If ($File = Get-ChildItem $Path | Where { $_.LastWriteTime -ge [datetime]::Now.AddMinutes(-15) }){
$smtp.send($message)}
write-host "Mail Sent"
Thanks
Try this condition:
if ((Get-ChildItem $Path | Where { $_.LastWriteTime -ge [datetime]::Now.AddMinutes(-15) }).Count -ge 1){ <# do something #> }

Using Powershell to Do Action Every Time a Specific Outlook Email is Received

I receive a lot of emails from people to copy a file from one file location to another. I would like my Powershell program to automate this process that whenever I receive an email with a specific subject line, my program completes the action above and sends an email to the sender that this has been completed. My copy and paste code, testing the path, and sending an email by themselves work. Running the code in its entirety doesn't give me an error but also doesn't do anything. I have left comments in the code below where I think the problems are (can't be sure though)
Add-Type -assembly "Microsoft.Office.Interop.Outlook"
$outlook = New-Object -ComObject Outlook.Application
$namespace = $Outlook.GetNameSpace("MAPI")
$inbox = $namespace.GetDefaultFolder([Microsoft.Office.Interop.Outlook.OlDefaultFolders]::olFolderInbox)
$emails = $inbox.Items | Where-Object {$_.subject -match ‘COPY FILE’} #I think might be wrong
if ($_.subject -match 'COPY FILE') #I think might be wrong
{
Copy-Item -Path ($oldLocation + $fileName) -Destination $newLocation
if (Test-Path -Path ($newLocation + $fileName))
{
$mail = $outlook.CreateItem(0)
$mail.To = $sender
$mail.Subject = "Completed"
$mail.Body = "File has been successfully moved"
$mail.Send()
}
else
{
$mail = $outlook.CreateItem(0)
$mail.To = $sender
$mail.Subject = "Failed"
$mail.Body = "File does not exist in $newLocation"
$mail.Send()
}
}
Your If statement is referring to $_ but there's no surrounding loop or pipeline.
Just a suggestion but maybe:
Add-Type -assembly "Microsoft.Office.Interop.Outlook"
$outlook = New-Object -ComObject Outlook.Application
$namespace = $Outlook.GetNameSpace("MAPI")
$inbox = $namespace.GetDefaultFolder([Microsoft.Office.Interop.Outlook.OlDefaultFolders]::olFolderInbox)
$emails = $inbox.Items | Where-Object {$_.subject -match ‘COPY FILE’} #I think might be wrong
$Emails |
ForEach-Object{
if ($_.subject -match 'COPY FILE') #I think might be wrong
{
Copy-Item -Path ($oldLocation + $fileName) -Destination $newLocation
if (Test-Path -Path ($newLocation + $fileName))
{
$mail = $outlook.CreateItem(0)
$mail.To = $sender
$mail.Subject = "Completed"
$mail.Body = "File has been successfully moved"
$mail.Send()
}
else
{
$mail = $outlook.CreateItem(0)
$mail.To = $sender
$mail.Subject = "Failed"
$mail.Body = "File does not exist in $newLocation"
$mail.Send()
}
}
}
Also; I don't know if they are defined elsewhere but I don't see any definition for $oldlocation, $filename, or $newlocation. I'd have thought you need to parse those out of the subject or body of the message.
$Sender, might need to be $_.Sender in this example.

Search for a file that matches a keyword, then attach it to an email

I've written a PowerShell script that searches a folder for a file that matches a keyword eg Japan and then adds the file as an attachment to an email.
The email sends correctly, however the file isn't attached.
Add-PSSnapin Microsoft.Exchange.Management.Powershell.Admin -ErrorAction
SilentlyContinue
$dir = "C:\Users\user\Desktop"
$file = Get-ChildItem -Path $dir | -Filter "$keyword" -Recurse | Select-Object
$keyword = "Japan"
$mailboxdata = (Get-MailboxStatistics | select DisplayName,TotalItemSize,TotalDeletedItemSize, ItemCount, LastLoggedOnUserAccount, LastLogonTime)
$mailboxdata | Export-Csv "$file"
$smtpServer = "192.168.1.100"
$att = New-Object Net.Mail.Attachment($file)
$msg = New-Object Net.Mail.MailMessage
$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
$msg.From = "email#mail.com"
$msg.To.Add("email#othermail.com")
$msg.Subject = "Notification from email server"
$msg.Body = "Attached is the email server mailbox report for Japan"
$msg.Attachments.Add($att)
$smtp.Send($msg)
$att.Dispose()
You've modified a script from another source (that sends Mailbox Statistics from Microsoft Exchange) and you've left in parts of it that you do not need.
$dir = "C:\Users\user\Desktop"
$keyword = "Japan"
$smtpServer = "192.168.1.100"
$file = Get-ChildItem -Path $dir -Filter "*$keyword*" -Recurse
$att = New-Object Net.Mail.Attachment($file)
$msg = New-Object Net.Mail.MailMessage
$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
$msg.From = "email#mail.com"
$msg.To.Add("email#othermail.com")
$msg.Subject = "Notification from email server"
$msg.Body = "Attached is the email server mailbox report for Japan"
$msg.Attachments.Add($att)
$smtp.Send($msg)
$att.Dispose()
I would use Send-MailMessage instead as it's syntax is much easier to use:
$dir = "C:\Users\user\Desktop"
$keyword = "Japan"
$Attachment = Get-ChildItem -Path $dir -Filter "*$keyword*" -Recurse
$From = "email#mail.com"
$To = "email#othermail.com"
$Subject = "Files matching: $keyword"
$Body = "Attached is the file for: $keyword"
$SMTPServer = "192.168.1.100"
Send-MailMessage -From $From -To $To -Subject $Subject -Body $Body -SmtpServer $SMTPServer -Attachments $Attachment.FullName

Remove-Item cmdlet not working properly

So I have a script that combs through a directory of about 1200 songs, the user selects one song, (which is then put into the $Selected variable) and then through "script magic" (I can provide the code if necessary, but I don't think it is for our purposes) an email is sent to an email account I need it sent to. I then want to delete the song from the directory aaaannnnndddd that is when I run into issues. Here is the code I originally tried to delete the song with:
Remove-Item C:\Users\woafr\Desktop\Songs\$Selected -recurse -force
And with that code I got hit with this error message:
Remove-Item : Cannot remove item C:\Users\woafr\Desktop\Songs\song.mp3: The process cannot access the file C:\Users\woafr\Desktop\Songs\song.mp3' because it is being used by another process
So I then read this artice and this Stack Overflow thread and this Server Fault thread and modified my code to this:
Get-ChildItem C:\Users\woafr\Desktop\Songs\$Selected -recurse -force | Remove-Item
And still got hit with the same errors. Is there something I can do here that will have me delete the songs, or will I have to do it by hand (the horror!)
Here is the whole script for reference:
# Search Engine part
$SearchInput = Read-Host "Enter song name here:"
$Items = Get-ChildItem C:\Users\woafr\Desktop\Songs -Recurse -Filter *$SearchInput*
IF (-Not $Items)
{Write-Host 'Nothing returned...
The search engine does not care about capitilization (so "That" and "that" are read the exact same by the search engine)
But it does care about punctuation (so "That''s" and "Thats" are not read the same by the search engine). Try Again' -ForegroundColor Red}
# Choose you this day what song you want
IF (-Not $Items)
{cmd /c pause}
$Index = 1
$Count = $Items.Count
foreach ($Item in $Items) {
$Item | Add-Member -MemberType NoteProperty -Name "Index" -Value $Index
$Index++
}
$Items | Select-Object Index, Attributes, LastWriteTime, Name | Out-Host
$Input = Read-Host "Select an item by index number, then press enter (1 to $Count)"
$Selected = $Items[$Input - 1]
Write-Host "You have selected $Selected"
# Email account the script is sending from
$SMTPServer = "smtp.gmail.com"
$SMTPPort = "587"
$Username = "myemail#gmail.com"
$Password = "mypassword"
# Email the script is sending
$to = "emailtoingest#gmail.com"
$subject = "Songs To Ingest"
$body = "Ingest attachment into WideOrbit"
$attachment = New-Object System.Net.Mail.Attachment("C:\Users\woafr\Desktop\Songs\$Selected")
$attachment.ContentDisposition.FileName = "$Selected"
# Act of sending the email
$message = New-Object System.Net.Mail.MailMessage
$message.subject = $subject
$message.body = $body
$message.to.add($to)
$message.from = $username
$message.attachments.add($attachment)
$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);
$smtp.EnableSSL = $true
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);
$smtp.send($message)
write-host "Mail Sent" -ForegroundColor Green
cmd /c pause
# Trying to delete the damn thing
Get-ChildItem C:\Users\woafr\Desktop\Songs\$Selected -recurse -force | Remove-Item
cmd /c pause
So the problem is send mail objects are locking the file ,try using this snippet just before your remove-item commandlet:
$smtp = $null
foreach ($attachment in $message.attachments){
$attachment.dispose();
}
$message.dispose();

Uploading to SharepointOnline subfolder using Powershell

it seems like I can upload a file to SPO's Site Collection URL but not the subfolder. For example, I can upload to "https://xyz.sharepoint.com/sites/Reporting", but not "https://xyz.sharepoint.com/sites/Reporting/Sales". Here's the working code's relevant bit:
$Username = "me#domain.com"
$Password = "Password"
$SiteCollectionUrl = "https://xyz.sharepoint.com/sites/Reporting"
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
$DocLibName = "Sales"
$Folder="C:\MySalesFolder"
Function Get-SPOCredentials([string]$UserName,[string]$Password)
{
$SecurePassword = $Password | ConvertTo-SecureString -AsPlainText -Force
return New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName, $SecurePassword)
}
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($SiteCollectionUrl)
$Context.Credentials = Get-SPOCredentials -UserName $UserName -Password $Password
#Retrieve list
$List = $Context.Web.Lists.GetByTitle($DocLibName)
$Context.Load($List)
$Context.ExecuteQuery()
#Upload file
Foreach ($File in (dir $Folder -File))
{
$FileStream = New-Object IO.FileStream($File.FullName,[System.IO.FileMode]::Open)
$FileCreationInfo = New-Object Microsoft.SharePoint.Client.FileCreationInformation
$FileCreationInfo.Overwrite = $true
$FileCreationInfo.ContentStream = $FileStream
$FileCreationInfo.URL = $File
$Upload = $List.RootFolder.Files.Add($FileCreationInfo)
$Context.Load($Upload)
$Context.ExecuteQuery()
I tried to hardcode "/Sales" subfolder but no luck. Anyone can point me in the right direction?
According to Trying to upload files to subfolder in Sharepoint Online via Powershell You will need to amend the FileCreationURL:
$FileCreationInfo.URL = $List.RootFolder.ServerRelativeUrl + "/" + $FolderName + "/" + $File.Name
I believe you just need to prepend $File.Name with the Folder path to your root directory.
Web.GetFolderByServerRelativeUrl Method:
Alternatively to attempting to Upload via List.RootFolder..., you can use the "GetFolderByServerRelativeUrl" method to get your Target Folder
$List = $Context.Web.Lists.GetByTitle($DocLibName)
$Context.Load($List.RootFolder)
$Context.ExecuteQuery()
$FolderName = "Sales"
$TargetFolder = $Context.Web.GetFolderByServerRelativeUrl($List.RootFolder.ServerRelativeUrl + "/" + $FolderName);
Then for upload you would use
$FileCreationInfo.URL = $File.Name
$UploadFile = $TargetFolder.Files.Add($FileCreationInfo)
$Context.Load($UploadFile)
$Context.ExecuteQuery()