Powershell script that searches network computers and sends back email

I need a Powershell script that will scan all computers on a network to find a file from a list of files and then send me an email telling me which computer has the file. I got this far

$computers = Get-ADComputer -filter *  | Select -Exp Name

$filenames = Get-Content "C:\filenamelist.txt"

foreach ($computer in $computers) {

foreach ($filename in $filenames) {
Get-ChildItem -Recurse -Force \\$computer\c$, \\$computer\d$ -ErrorAction SilentlyContinue | Where-Object { ($_.PSIsContainer -eq $false) -and  ( $_.Name -eq "$filename") } | Select-Object Name,Directory| Export-Csv C:\FoundFiles.csv -nti -append

this will scan all computers on the network to finding files found from a file called filenamelist.txt. what i need help with is where to input the code for sending the email in order for it to only send an email if the file is actually found. If you could please test to see if my code works in the firstplace and then the email thing it would be much appreciated. Thanks to anyone who can help
Brady McDermottLearningAsked:
Who is Participating?
That code would be horribly slow, having to enumerate all files multiple times on each computer (once for each name in your list).
Not modifying your approach too much, this would be a little better.
$filenames = Get-Content "C:\filenamelist.txt"
$outfile = "C:\FoundFiles.csv"
Get-ADComputer -filter * | Select -Exp Name | ForEach-Object {
    $computer = $_
    Get-ChildItem -Recurse -Force \\$computer\c$, \\$computer\d$ -ErrorAction SilentlyContinue |
     Where-Object { ($_.PSIsContainer -eq $false) -and  ( $filenames -contains $_.Name ) } |
     Select-Object Name,Directory,@{n="Computer";e={$computer}}
} | Export-Csv $outfile -nti -append

If ( (Get-Item $outfile).Length -gt 0 )
    Send-MailMessage -To "a@example.com" -From "c@example.com" -Subject "found files" -Attachments $outfile -SmtpServer "smtp.example.com"

Open in new window

Making use of PS Remoting (fan-out) so that you don't have to process each machine in a serial fashion and all the drive data across the network would speed things up a lot.

Using the WMI class CIM_DataFile would be faster than Get-ChildItem.  An example of a function that makes use of it is at https://powershell.org/2013/01/29/find-files-with-wmi-and-powershell/
(I'll post it below).
Function Get-CIMFile {
#comment based help is here

[Parameter(Position=0,Mandatory=$True,HelpMessage="What is the name of the file?")]

 strip off any trailing characters to drive parameter
 that might have been passed.
If ($Drive.Length -gt 2) {

Write-Verbose "Searching for $Name on Drive $Drive on computer $Computername."

Normally you might think to simply split the name on the . character. But
you might have a filename like myfile.v2.dll so that won't work. In a case
like this the extension would be everything after the last . and the filename
everything before.

So instead I'll use the substring method to "split" the filename string.

#get the index of the last .
$index = $name.LastIndexOf(".")
#get the first part of the name
#get the last part of the name

$filter = "Filename='$filename' AND extension='$extension' AND Drive='$drive'"
Write-Verbose $filter

#get all instances of the file and write the WMI object to the pipeline
Get-WmiObject -Class CIM_Datafile -Filter $filter -ComputerName $Computername -Asjob:$AsJob

Open in new window

Some work would need to be done to adapt it to meet your exact needs.
All Courses

From novice to tech pro — start learning today.