Search code examples
powershellemail-attachments

How to attach files to email using Get-ChildItem in Powershell


I am trying to write a Powershell script that does the following:

  1. Check all files in a directory for a valid string
  2. Take every file that contains that valid string and then send them as an email attachment

I do not care if one email is sent with all of the valid files or if an email is sent for each valid file.

The following code is what I have but it errors out when trying to attach the files saying Send-MailMessage : Cannot find drive. A drive with the name '

$ValidFiles = Get-ChildItem -Path C:\Results -Recurse |
                Select-String -Pattern "Test" |
                  Select-Object -Unique Path

foreach ($ValidFile in $ValidFiles)
{

    $From = 'test <test@test.com>'
    $To = 'me <me@test.com>'
    $Subject = "Valid File Found"
    $Username = "Test-Domain\test"
    $Password = ConvertTo-SecureString "notrealpassword" -AsPlainText -Force
    $Creds = New-Object System.Management.Automation.PSCredential($username, $password)
    $Body = "Please review the attached files"
    $Attachment = $ValidFile | Out-String
    $SMTPServer = "test-com.mail.protection.outlook.com"

    Send-MailMessage -From $From -To $To -Subject $Subject -Credential ($Creds) -Attachments $Attachment -UseSsl -Body $Body -DeliveryNotificationOption OnSuccess, OnFailure -SmtpServer $SMTPServer
}

Any help is greatly appreciated.


Solution

  • First, make sure that $ValidFiles contains only strings (file paths):

    $ValidFiles = Get-ChildItem -Path C:\Results -Recurse | 
                    Select-String -List -Pattern "Test" | 
                      ForEach-Object Path
    
    • Adding -List to Select-String makes the search stop at the first match found in a given file, which obviates the need for Select-Object -Unique.

    • Select-Object outputs [pscustomobject] instances with the specified property/properties, even if only one property Path is specified; while you could use -ExpandProperty Path instead to get just the .Path property value, it is simpler to use ForEach-Object with the property name instead.

    Then, use $ValidFile - which is now a path string - directly as the -Attachments argument (which is [string[]]-typed, but also accepts a scalar [string] instance (single string)).

    • Generally, do not use Out-String, unless you want a formatted for display representation of the input object(s).