Powershell remove-item won't delete files - powershell

I have a PowerShell 5.1 script that should delete some files. However, when I try to delete them, neither del nor remove-item appear to be working. I have alredy set the execution policy to Unrestricted, and launched the ISE in admin mode. Even moving the file with Move-Item didn't work.
My code:
$startROMFolderPath = "C:\Users\VincentGuttmann\Desktop\retropie-mount\roms" #Pleae enter the path to your current ROM folder here, ending in the roms folder. Note that this script will only work if the ROMs are inside the RetroPie folder.
$deleteROMFolder = $startROMFolderPath + "\delete"
Write-Host #"
Hello!
Welcome to my ROM Sorting program!
There are three main ROM types:
The ROMs that are "known good", which are marked with this tag: [!],
the bad dumps, so "known bad", which are marked [b].
Then there are the ROMs where we don't know.
The ROMs that are known good will be left in the folder.
The bad dumps will be deleted right away, as well as the ROMs which are neither German nor English
If you haven't put in the paths to your current ROM folder,
please exit the program now by pressing enter and then "n" without quotation marks.
"#
$inputted = Read-Host -Prompt 'Have you changed the paths accordingly? Yes: (y), No: anything else than (y)'
$i = 0
if($inputted -eq "y")
{
$foldersOld = #()
Get-ChildItem $startROMFolderPath -Attributes Directory |
foreach {
$foldersOld += $_
}
foreach ($name in $foldersOld) {
$currentROMFolderPath = $StartROMFolderPath + "\" + $name
$ROMList = #()
Get-ChildItem $currentROMFolderPath -File |
foreach {
$currentROMPath = $currentROMFolderPath + "\" + $_
$containsBad = $_ -match "\[b.\]"
$containsGood = $_ -match "\[!\]"
$containsLang = $_ -match ".*(\([UE]+\))|(\(U\).*\(E.*\))|(\(E.*\).*\(U\))|(\(E.*\))|(\([UKNG4A]+\))|(\(Unl\))"
if($containsBad)
{
write-host "====================================="
Write-Host $_
Write-Host "contains bad"
write-host "====================================="
Remove-Item -Path $currentROMPath -Force
}
#Put "!$containsGood -and !$containsLang" into the next bracket if you want to delete all ROMS that are neither good nor in the correct Language.
#For just keeping ROMs in the corect language, plase use "!$containsLang"
elseif(!$containsGood -and !$containsLang)
{
write-host "====================================="
Write-Host $_
Write-Host "Contains no good and no lang"
write-host $currentROMPath
write-host "====================================="
Remove-Item -Path $currentROMPath -Force
}
}
}
}
else
{
exit
}
exit

Related

Powershell Throw Causing Variables to Clear?

My PowerShell script just checks multiple servers to make sure the input* and output* directories are clear of any files.
I'm simply trying to output to console the results of a GCI call prior to throwing an error message. However, when I uncomment the "throw" line, the $inputFiles and $outputFiles no longer output to the console. Below is the code:
$allServers = #(
"server1.com",
"server2.com")
foreach ($server in $allServers) {
$inputFiles = Get-ChildItem -Path "\\$server\C$\jobs\statements\input*\" -Recurse | Where-Object {! $_.PSIsContainer } | Select FullName
$outputFiles = Get-ChildItem -Path "\\$server\C$\jobs\statements\output*\" -Recurse | Where-Object {! $_.PSIsContainer } | Select FullName
if ($inputFiles -eq $NULL -and $outputFiles -eq $NULL) {
Write-Host "Environment is ready for statement processing."
}
else {
Write-Host "Environment is NOT ready for statement processing."
Write-Host "The following files exist in input/output: `n"
$inputFiles
$outputFiles
#Throw "Files exist in input/output. See above for details."
}
}
Below is the console output:
Environment is NOT ready for statement processing.
The following files exist in input/output:
Environment is NOT ready for statement processing.
The following files exist in input/output:
FullName
--------
\\server1.com\C$\jobs\statements\input\asdasd.txt
\\server1.com\C$\jobs\statements\input_254\asdasd.txt
\\server1.com\C$\jobs\statements\input_test\asdasd.txt
\\server2.com\C$\jobs\statements\input\CUSSTAT10302021.245
\\server2.com\C$\jobs\statements\input\CUSSTAT11312021
\\server2.com\C$\jobs\statements\input\CUSSTAT11312021.zip
And below is the console output when I uncomment the "throw" line:
Environment is NOT ready for statement processing.
The following files exist in input/output:
Files exist in input/output. See above for details.
At C:\jobs\statements\bin\Statements-EnvironmentCheck.ps1:47 char:9
+ Throw "Files exist in input/output. See above for details."
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (Files exist in ...ve for details.:String) [], RuntimeException
+ FullyQualifiedErrorId : Files exist in input/output. See above for details.
I know I have some error output cleanup to perform in order to include all the servers that might have files present, but please ignore that for now.
What you're experiencing is explained in this answer and this answer, basically you need to implement Out-Host \ Out-Default:
$inputFiles, $outputFiles | Out-Host # Should fix the problem
# possibly `throw` might require this too
throw "Files exist in input/output. See above for details." | Out-Host
However, I feel is worth showing you a better way to approach your code, returning a unified array of objects which you can filter, sort and export.
$allServers = #(
"server1.com"
"server2.com"
)
$result = foreach ($server in $allServers) {
# use `-File` instead of `! $_.PSIsContainer`
$out = #{
in = Get-ChildItem "\\$server\C$\jobs\statements\input*\" -Recurse -File
out = Get-ChildItem "\\$server\C$\jobs\statements\output*\" -Recurse -File
}
# if $out['in'] and $out['out'] are `$null`, Ready is `$true`
[pscustomobject]#{
Ready = -not($out['in'] -or $out['out'])
Server = $server
Files = $out
}
}
Now, if you want to see which servers are Ready (no files in input and output):
$result.where{ $_.Ready }
And if you want to see which servers are not Ready, and have a list of the files:
$result.where{ -not $_.Ready }.foreach{
foreach($file in $_.Files.PSBase.Values.FullName) {
[pscustomobject]#{
Server = $_.Server
Files = $file
}
}
}

Powershell - Find a specific file by name recursively in folder\folders

doing some scripting fun with looking for specific file by input.
i want to search specific file by name for example: "abc*" with the prefix either it will be abc.txt, or abc.doc, or what ever...
search recursively in folders, and print if it exists or not.
here is the script i've got so far:
[void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')
Function Get-ItemName {
$Global:ItemName = [Microsoft.VisualBasic.Interaction]::InputBox('Enter a Filename', 'File Name')
}
Get-ItemName
$itemList = Get-ChildItem "\\path_of_folder_with_many_files" -Recurse
$checkItems = 'true'
foreach ($item in $itemList) {
if ((Test-Path -LiteralPath $item) -eq $true -and (Name -like $ItemName)) {
Write-Host "$item - Found" -ForegroundColor Greed
}
elseif ((Test-Path -LiteralPath $item) -eq $false) {
Write-Host "$item - Not Found" -ForegroundColor Red
$checkItems = 'false'
}
}
if ($checkItems -eq $false){
echo ""
Write-Host "Some files was not found, Build Failed" -ForegroundColor Red
exit 1
}
but all it does is printing list of the files and " - Not Found".
and i do have files named "abc.txt" and "abc.doc" and many many more files.
oh yeah and the reason the "find files" script is so long, its because i want to use this powershell script later on a build, and crush it if files doesnt exists.
any ideas whats wrong here?
Either have your function return what was entered in the box and use that or remove that function completely as I have done below:
Add-Type -AssemblyName Microsoft.VisualBasic
$itemName = [Microsoft.VisualBasic.Interaction]::InputBox('Enter a Filename', 'File Name')
if (![string]::IsNullOrWhiteSpace($itemName)) {
# only search for files if there was anything entered in the box
$itemList = #(Get-ChildItem "\\path_of_folder_with_many_files" -Filter "*$itemName*" -File -Recurse)
# now do something with the array of FileInfo objects
# for demo just show how many files were found using the $itemName
Write-Host "Found $($itemList.Count) files with search name '$itemName'"
}
else {
write-host "Nothing was entered in the inputbox.."
}
As you can see, you don't need to use Test-Path, because all files returned by Get-ChildItem of course do exist.
Parameter -Filter here is used with wildcards to search for files with $itemName in their name
Adding switch -File makes sure only files are searched, not folders aswell
Surrounding Get-ChildItem with #() forces the result to be an array, so you can work with the .Count property

move files, depending on their first letter - powershell

I have 1 disk, on my home server, which has all my media in, and where my films download to. I wonder if you could suggest a quick way to move files, to different hard drives, on the letter they start with. E.g my H drive has all my media, I would like files beginning with A-F to drive D, files G-L to drive F and files M-Z to drive E. So far I have ‘Move-Item H:\done\C* D:\ -Force’ line for every letter of the alphabet. Just wondered if there was a quicker was of moving the files.
A work colleague provided me with a script, but it doesn't work, and not sure if its me doing something wrong or the script:
#get a list of files at the source
$files = gci H:\done
#loop through each item in the variable "$files" which will then on be referenced to using the variable "$file"
foreach($file in $files){
#assign the drive letter using a switch statement. Switch statements are a quick way to return a new value based on if a condition is met... in this case if the first letter of the input matches the regex statement.
$drive = switch -regex ($file.basename[0]) {
'[A-F]' {'D:\'}
'[G-L]' {'F:\'}
'[M-Z]' {'E:\'}
}
#quick way to show progress
write-host "Moving $($file.Name) to $drive" -f Cyan
#perform the move
Move-Item $file.FullName $drive -Force -Verbose
}
This should do the trick:
$files = dir C:\Users\Neko\Desktop #Whatever directory
$var1 = #(65..70);
$var2 = #(71..76);
$var3 = #(77..90);
echo work3
for($i=0;$i -lt $var1.length;$i++){ [char]$var1[$i] = $var1[$i]; }
for($i=0;$i -lt $var2.length;$i++){ [char]$var2[$i] = $var2[$i]; }
for($i=0;$i -lt $var3.length;$i++){ [char]$var3[$i] = $var3[$i]; }
foreach($file in $files){
if($file.name[0] -in $var1){$drive = 'D:\'}
if($file.name[0] -in $var2){$drive = 'F:\'}
if($file.name[0] -in $var3){$drive = 'E:\'}
write-host "Moving $($file.Name) to $drive" -f Cyan
MI -path "$file.fullname" -destination $drive -Force
}
This is very basic powershell coding. I was able to sort the files into $var1, $var2, and $var3 categories since they listed ascii characters for the letters you wanted and then converted them to letters using the for loops, a bit convoluted but this is the easiest way to do this in my opinion. You then loop through the $files variable where it takes everything from the directory you in the variable, in my case C:Users\Neko\Desktop\* and for you it would be H:\done\* and seperates them into categories from the $var1 $var2 $var3 we mentioned earlier and sets the $drive variable. It then moves the files.
ERRORS WITH YOUR COLLEAGUE'S CODE
[A-F] does is not the same as a number group like (1..100) and would not do anything except produce errors.
$file.basename isn't necessary compared to just the normal $file.name if you are only going to take the first character. Its just typing extra letters.
Overall, it was good, but not enough to accomplish your task. Full code for your case:
$files = dir H:\done
$var1 = #(65..70);
$var2 = #(71..76);
$var3 = #(77..90);
echo work3
for($i=0;$i -lt $var1.length;$i++){ [char]$var1[$i] = $var1[$i]; }
for($i=0;$i -lt $var2.length;$i++){ [char]$var2[$i] = $var2[$i]; }
for($i=0;$i -lt $var3.length;$i++){ [char]$var3[$i] = $var3[$i]; }
foreach($file in $files){
if($file.name[0] -in $var1){$drive = 'D:\'}
if($file.name[0] -in $var2){$drive = 'F:\'}
if($file.name[0] -in $var3){$drive = 'E:\'}
write-host "Moving $($file.Name) to $drive" -f Cyan
MI -path "$file.fullname" -destination $drive -Force
}

Powershell output formatting?

I have a script that scans for a specific folder in users AppData folder. If it finds the folder, it then returns the path to a txt file. So we can see the computer name and username where it was found.
I would like to be able to format the what is actually written to the text file, so it removes everything from the path except the Computer and User names.
Script:
foreach($computer in $computers){
$BetterNet = "\\$computer\c$\users\*\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm"
Get-ChildItem $BetterNet | ForEach-Object {
$count++
$betternetCount++
write-host BetterNet found on: $computer
Add-Content "\\SERVERNAME\PowershellScans\$date\$time\BetterNet.txt" $_`n
write-host
}
}
The text files contain information like this
\\computer-11-1004S10\c$\users\turtle\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm
\\computer-1004-24S\c$\users\camel\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm
\\computer-1004-23S\c$\users\rabbit\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm
If you have each line in a form of the string $string_containing_path then it is easy to split using split method and then add index(1) and (4) that you need:
$afterSplit = $string_containing_path.Split('\')
$stringThatYouNeed = $afterSplit[1] + " " + $afterSplit[4]
You can also use simple script that will fix your current logs:
$path_in = "C:\temp\list.txt"
$path_out= "C:\temp\output.txt"
$reader = [System.IO.File]::OpenText($path_in)
try {
while($true){
$line = $reader.ReadLine()
if ($line -eq $null) { break }
$line_after_split_method = $line.Split('\')
$stringToOutput = $line_after_split_method[1] + " " + $line_after_split_method[4] + "`r`n"
add-content $path_out $stringToOutput
}
add-content $path_out "End"
}
finally {
$reader.Close()
}
If you split your loop into two foreach loops, one for computer and user directory it would be easier to output the name of the user directory.
$output = foreach($computer in $computers){
$UserDirectories = Get-ChildItem "\\$computer\c$\users\" -Directory
foreach ($Directory in $UserDirectories) {
$BetterNet = Get-ChildItem (Join-Path $Directory.fullname "\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm")
Add-Content "\\SERVERNAME\PowershellScans\$date\$time\BetterNet.txt" "$computer $($Directory.name)`r`n"
write-host BetterNet found on: $computer
$BetterNet
}
}
$output.count

How to retrieve a recursive directory and file list from PowerShell excluding some files and folders?

I want to write a PowerShell script that will recursively search a directory, but exclude specified files (for example, *.log, and myFile.txt), and also exclude specified directories, and their contents (for example, myDir and all files and folders below myDir).
I have been working with the Get-ChildItem CmdLet, and the Where-Object CmdLet, but I cannot seem to get this exact behavior.
I like Keith Hill's answer except it has a bug that prevents it from recursing past two levels. These commands manifest the bug:
New-Item level1/level2/level3/level4/foobar.txt -Force -ItemType file
cd level1
GetFiles . xyz | % { $_.fullname }
With Hill's original code you get this:
...\level1\level2
...\level1\level2\level3
Here is a corrected, and slightly refactored, version:
function GetFiles($path = $pwd, [string[]]$exclude)
{
foreach ($item in Get-ChildItem $path)
{
if ($exclude | Where {$item -like $_}) { continue }
$item
if (Test-Path $item.FullName -PathType Container)
{
GetFiles $item.FullName $exclude
}
}
}
With that bug fix in place you get this corrected output:
...\level1\level2
...\level1\level2\level3
...\level1\level2\level3\level4
...\level1\level2\level3\level4\foobar.txt
I also like ajk's answer for conciseness though, as he points out, it is less efficient. The reason it is less efficient, by the way, is because Hill's algorithm stops traversing a subtree when it finds a prune target while ajk's continues. But ajk's answer also suffers from a flaw, one I call the ancestor trap. Consider a path such as this that includes the same path component (i.e. subdir2) twice:
\usr\testdir\subdir2\child\grandchild\subdir2\doc
Set your location somewhere in between, e.g. cd \usr\testdir\subdir2\child, then run ajk's algorithm to filter out the lower subdir2 and you will get no output at all, i.e. it filters out everything because of the presence of subdir2 higher in the path. This is a corner case, though, and not likely to be hit often, so I would not rule out ajk's solution due to this one issue.
Nonetheless, I offer here a third alternative, one that does not have either of the above two bugs. Here is the basic algorithm, complete with a convenience definition for the path or paths to prune--you need only modify $excludeList to your own set of targets to use it:
$excludeList = #("stuff","bin","obj*")
Get-ChildItem -Recurse | % {
$pathParts = $_.FullName.substring($pwd.path.Length + 1).split("\");
if ( ! ($excludeList | where { $pathParts -like $_ } ) ) { $_ }
}
My algorithm is reasonably concise but, like ajk's, it is less efficient than Hill's (for the same reason: it does not stop traversing subtrees at prune targets). However, my code has an important advantage over Hill's--it can pipeline! It is therefore amenable to fit into a filter chain to make a custom version of Get-ChildItem while Hill's recursive algorithm, through no fault of its own, cannot. ajk's algorithm can be adapted to pipeline use as well, but specifying the item or items to exclude is not as clean, being embedded in a regular expression rather than a simple list of items that I have used.
I have packaged my tree pruning code into an enhanced version of Get-ChildItem. Aside from my rather unimaginative name--Get-EnhancedChildItem--I am excited about it and have included it in my open source Powershell library. It includes several other new capabilities besides tree pruning. Furthermore, the code is designed to be extensible: if you want to add a new filtering capability, it is straightforward to do. Essentially, Get-ChildItem is called first, and pipelined into each successive filter that you activate via command parameters. Thus something like this...
Get-EnhancedChildItem –Recurse –Force –Svn
–Exclude *.txt –ExcludeTree doc*,man -FullName -Verbose
... is converted internally into this:
Get-ChildItem | FilterExcludeTree | FilterSvn | FilterFullName
Each filter must conform to certain rules: accepting FileInfo and DirectoryInfo objects as inputs, generating the same as outputs, and using stdin and stdout so it may be inserted in a pipeline. Here is the same code refactored to fit these rules:
filter FilterExcludeTree()
{
$target = $_
Coalesce-Args $Path "." | % {
$canonicalPath = (Get-Item $_).FullName
if ($target.FullName.StartsWith($canonicalPath)) {
$pathParts = $target.FullName.substring($canonicalPath.Length + 1).split("\");
if ( ! ($excludeList | where { $pathParts -like $_ } ) ) { $target }
}
}
}
The only additional piece here is the Coalesce-Args function (found in this post by Keith Dahlby), which merely sends the current directory down the pipe in the event that the invocation did not specify any paths.
Because this answer is getting somewhat lengthy, rather than go into further detail about this filter, I refer the interested reader to my recently published article on Simple-Talk.com entitled Practical PowerShell: Pruning File Trees and Extending Cmdlets where I discuss Get-EnhancedChildItem at even greater length. One last thing I will mention, though, is another function in my open source library, New-FileTree, that lets you generate a dummy file tree for testing purposes so you can exercise any of the above algorithms. And when you are experimenting with any of these, I recommend piping to % { $_.fullname } as I did in the very first code fragment for more useful output to examine.
The Get-ChildItem cmdlet has an -Exclude parameter that is tempting to use but it doesn't work for filtering out entire directories from what I can tell. Try something like this:
function GetFiles($path = $pwd, [string[]]$exclude)
{
foreach ($item in Get-ChildItem $path)
{
if ($exclude | Where {$item -like $_}) { continue }
if (Test-Path $item.FullName -PathType Container)
{
$item
GetFiles $item.FullName $exclude
}
else
{
$item
}
}
}
Here's another option, which is less efficient but more concise. It's how I generally handle this sort of problem:
Get-ChildItem -Recurse .\targetdir -Exclude *.log |
Where-Object { $_.FullName -notmatch '\\excludedir($|\\)' }
The \\excludedir($|\\)' expression allows you to exclude the directory and its contents at the same time.
Update: Please check the excellent answer from msorens for an edge case flaw with this approach, and a much more fleshed out solution overall.
Recently, I explored the possibilities to parameterize the folder to scan through and the place where the result of recursive scan will be stored. At the end, I also did summarize the number of folders scanned and number of files inside as well. Sharing it with community in case it may help other developers.
##Script Starts
#read folder to scan and file location to be placed
$whichFolder = Read-Host -Prompt 'Which folder to Scan?'
$whereToPlaceReport = Read-Host -Prompt 'Where to place Report'
$totalFolders = 1
$totalFiles = 0
Write-Host "Process started..."
#IMP separator ? : used as a file in window cannot contain this special character in the file name
#Get Foldernames into Variable for ForEach Loop
$DFSFolders = get-childitem -path $whichFolder | where-object {$_.Psiscontainer -eq "True"} |select-object name ,fullName
#Below Logic for Main Folder
$mainFiles = get-childitem -path "C:\Users\User\Desktop" -file
("Folder Path" + "?" + "Folder Name" + "?" + "File Name " + "?"+ "File Length" )| out-file "$whereToPlaceReport\Report.csv" -Append
#Loop through folders in main Directory
foreach($file in $mainFiles)
{
$totalFiles = $totalFiles + 1
("C:\Users\User\Desktop" + "?" + "Main Folder" + "?"+ $file.name + "?" + $file.length ) | out-file "$whereToPlaceReport\Report.csv" -Append
}
foreach ($DFSfolder in $DFSfolders)
{
#write the folder name in begining
$totalFolders = $totalFolders + 1
write-host " Reading folder C:\Users\User\Desktop\$($DFSfolder.name)"
#$DFSfolder.fullName | out-file "C:\Users\User\Desktop\PoC powershell\ok2.csv" -Append
#For Each Folder obtain objects in a specified directory, recurse then filter for .sft file type, obtain the filename, then group, sort and eventually show the file name and total incidences of it.
$files = get-childitem -path "$whichFolder\$($DFSfolder.name)" -recurse
foreach($file in $files)
{
$totalFiles = $totalFiles + 1
($DFSfolder.fullName + "?" + $DFSfolder.name + "?"+ $file.name + "?" + $file.length ) | out-file "$whereToPlaceReport\Report.csv" -Append
}
}
# If running in the console, wait for input before closing.
if ($Host.Name -eq "ConsoleHost")
{
Write-Host ""
Write-Host ""
Write-Host ""
Write-Host " **Summary**" -ForegroundColor Red
Write-Host " ------------" -ForegroundColor Red
Write-Host " Total Folders Scanned = $totalFolders " -ForegroundColor Green
Write-Host " Total Files Scanned = $totalFiles " -ForegroundColor Green
Write-Host ""
Write-Host ""
Write-Host "I have done my Job,Press any key to exit" -ForegroundColor white
$Host.UI.RawUI.FlushInputBuffer() # Make sure buffered input doesn't "press a key" and skip the ReadKey().
$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") > $null
}
##Output
##Bat Code to run above powershell command
#ECHO OFF
SET ThisScriptsDirectory=%~dp0
SET PowerShellScriptPath=%ThisScriptsDirectory%MyPowerShellScript.ps1
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File ""%PowerShellScriptPath%""' -Verb RunAs}";
A bit late, but try this one.
function Set-Files($Path) {
if(Test-Path $Path -PathType Leaf) {
# Do any logic on file
Write-Host $Path
return
}
if(Test-Path $path -PathType Container) {
# Do any logic on folder use exclude on get-childitem
# cycle again
Get-ChildItem -Path $path | foreach { Set-Files -Path $_.FullName }
}
}
# call
Set-Files -Path 'D:\myFolder'
Commenting here as this seems to be the most popular answer on the subject for searching for files whilst excluding certain directories in powershell.
To avoid issues with post filtering of results (i.e. avoiding permission issues etc), I only needed to filter out top level directories and that is all this example is based on, so whilst this example doesn't filter child directory names, it could very easily be made recursive to support this, if you were so inclined.
Quick breakdown of how the snippet works
$folders << Uses Get-Childitem to query the file system and perform folder exclusion
$file << The pattern of the file I am looking for
foreach << Iterates the $folders variable performing a recursive search using the Get-Childitem command
$folders = Get-ChildItem -Path C:\ -Directory -Name -Exclude Folder1,"Folder 2"
$file = "*filenametosearchfor*.extension"
foreach ($folder in $folders) {
Get-Childitem -Path "C:/$folder" -Recurse -Filter $file | ForEach-Object { Write-Output $_.FullName }
}