Powershell where filter not working - powershell

I have the following simple code:
remove-item -path $path | where($_ -like "*IE*")
But for some reason I get an error due to the wildcards

Your script above has a few errors. I'll try to help you out with them.
First and foremost, the Remove-Item cmdlet doesn't provide any output for your where line. You've got to get it first. I'm going to assume since you want to filter out items that don't match IE, you're getting multiple files from a directory. If this is only a single file, all you need to do is Remove-Item -Path $Path. If it's a directory, the cmdlet is Get-ChildItem
Get-ChildItem -Path $Path
Now that you have all of your items from $Path, we need to filter them. You do this with Where-Object. Like this...
Get-ChildItem -Path $Path | Where-Object
This is where the next issue comes in. You are using -like when I think you want -match. Also, your $_ is going to signify the entire object. We need to match a property of the object. It'd look like this
Get-ChildItem -Path $Path | Where-Object -FilterScript { $_.PROPERTYNAME -match "IE"}
Now that we have our objects, and we have them sorted, it's time to remove them. We do this using the Remove-Item cmdlet, from above. Please notice that this time, it's at the end of the pipeline, rather than the beginning.
Get-ChildItem -Path $Path | Where-Object -FilterScript { $_.PROPERTYNAME -match "IE"} | Remove-Item
If you don't want to confirm each and every one (and you're sure these are the items you want to remove), add -Confirm:$false after Remove-Item. Otherwise, you'll have to confirm in the console every file you want to remove.
I really hope this helps!

Related

Copying files to specific folder declared in a CSV file using Powershell Script

i am quite new to powershell and i am trying to make a script that copy files to certain folders that are declared in a CSV file. But till now i am getting errors from everywhere and can't find nothing to resolve this issue.
I have this folders and .txt files created in the same folder as the script.
Till now i could only do this:
$files = Import-Csv .\files.csv
$files
foreach ($file in $files) {
$name = $file.name
$final = $file.destination
Copy-Item $name -Destination $final
}
This is my CSV
name;destination
file1.txt;folderX
file2.txt;folderY
file3.txt;folderZ
As the comments indicate, if you are not using default system delimiters, you should make sure to specify them.
I also recommend typically to use quotes for your csv to ensure no problems with accidentally including an entry that includes the delimiter in the name.
#"
"taco1.txt";"C:\temp\taco2;.txt"
"# | ConvertFrom-CSV -Delimiter ';' -Header #('file','destination')
will output
file destination
---- -----------
taco1.txt C:\temp\taco2;.txt
The quotes make sure the values are correctly interpreted. And yes... you can name a file foobar;test..txt. Never underestimate what users might do. 😁
If you take the command Get-ChildItem | Select-Object BaseName,Directory | ConvertTo-CSV -NoTypeInformation and review the output, you should see it quoted like this.
Sourcing Your File List
One last tip. Most of the time I've come across a CSV for file input lists a CSV hasn't been needed. Consider looking at grabbing the files you in your script itself.
For example, if you have a folder and need to filter the list down, you can do this on the fly very easily in PowerShell by using Get-ChildItem.
For example:
$Directory = 'C:\temp'
$Destination = $ENV:TEMP
Get-ChildItem -Path $Directory -Filter *.txt -Recurse | Copy-Item -Destination $Destination
If you need to have more granular matching control, consider using the Where-Object cmdlet and doing something like this:
Get-ChildItem -Path $Directory -Filter *.txt -Recurse | Where-Object Name -match '(taco)|(burrito)' | Copy-Item -Destination $Destination
Often you'll find that you can easily use this type of filtering to keep CSV and input files out of the solution.
example
Using techniques like this, you might be able to get files from 2 directories, filter the match, and copy all in a short statement like this:
Get-ChildItem -Path 'C:\temp' -Filter '*.xlsx' -Recurse | Where-Object Name -match 'taco' | Copy-Item -Destination $ENV:TEMP -Verbose
Hope that gives you some other ideas! Welcome to Stack Overflow. 👋

Powershell script which will search folders with regex and which will delete files older than XX

I need a powershell script ;
it must search some subfolders which folders names are starting with character between 1 and 6 (like 1xxxx or 2xxx)
and using the name of these folders as variable it must look under each folder for the *.XML files which are older than 30 min
and if it finds them it must delete it.
there may be more than one folder at same time, which are providing the same conditions so IMO using an array is a good choice. But I'm always open to other ideas.
Anybody can help me please ?
Basically I was using this before the need changes but now it doesnt help me.
powershell -nologo -command Get-ChildItem -Path C:\geniusopen\inbox\000\ready\processed | Where CreationTime -lt (Get-Date).AddDays(-10) | remove-item
Thank you
You can do something like the following and just remove -WhatIf if you are satisfied with the results:
$Time = (Get-Date).AddMinutes(-30)
Get-ChildItem -Path 'C:\MostCommonLeaf' -Recurse -File -Filter '*.xml' |
Where {$_.CreationTime -lt $Time -and (Split-Path $_.DirectoryName -Leaf) -match '^[1-6]' -and $_.Extension -eq '.xml'} |
Remove-Item -WhatIf
MostCommonLeaf would be the lowest level folder that could start as your root search node. We essentially don't want to traverse directories for nothing.
You could potentially make the script above better if you know more about your directory structure. For example, if it is predictable within the path where the 1xxx folders will be, you can construct the -Path parameter to use the [1-6] range wildcard. -Filter '*.xml' could also return .xmls files for example, so that's why there is additional extension condition in the Where.
Using -Recurse and -Include together generally results in much slower queries. So even if tempted, I would avoid a solution that uses those together.
If there are millions of files/directories, a different command construction could be better. Running Split-Path millions of times could be less efficient than just matching on the directory name, e.g. where {$_.DirectoryName -match '\\[1-6][^\\]*$'}.
I think you are looking for something like this:
$limit = (Get-Date).AddMinutes(-30)
$path = "C:\Users\you\xxx"
$Extension = "*.xml"
Get-ChildItem -Path $path -Filter $Extension -Force | Where-Object {$_.CreationTime -lt $limit} | Remove-Item
I haven't tested it though.
Keep in mind whether you need: $.CreationTime or $.LastWriteTime

Powershell: Move file from one directory to another, based on string within file

Looking around the site and can't seem to find some answers for myself.
I'm looking to write a script, that will enable me to move files from one destination to another, based on the contents within the file.
To get into Specifics
Source Destination - V:\SW\FromSite
Copy to Destination - V:\SW\ToSW
FileType - .txt
String - test
Ideally I'd also like to ONLY have the script search files that begin with 7. These are unique identifiers to a region.
Pulling my hair out a bit trying.
I was using the below, which runs without error, but does nothing.
$DestDir = "V:\SW\FromSite"
$SrcDir = "V:\SW\ToSW"
$SearchString = "test"
gci $SrcDir -filter 7*.txt | select-string $SearchString | select path |
move-item -dest $DestDir -whatif
Here's what I would do, though I'm sure there's a more streamlined way to do it.
$files = gci $SrcDir -filter 7*.txt
$files | %{
if ((select-string -path $_.FullName -pattern $SearchString) -ne $null) {
move-item -path $_.FullName -dest $DestDir
}
}
So did some more messing around and the below is working perfectly for what I need
get-childitem "<SourceFolder>" -filter 7*.txt -
recurse | select-string -list -pattern "test" | move -dest "<DestinationFolder>"
Thanks all for the help
Not sure if I missed something (didn't tried it on my machine) - but as long as you pass the -whatif option, move-item "shows what would happen if the cmdlet runs. The cmdlet is not run."; see https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/move-item.
So probably it would have been sufficient to just remove the -whatif from the initial statement.

Delete files containing string

How can I delete all files in a directory that contain a string using powershell?
I've tried something like
$list = get-childitem *.milk | select-string -pattern "fRating=2" | Format-Table Path
$list | foreach { rm $_.Path }
And that worked for some files but did not remove everything. I've tried other various things but nothing is working.
I can easily get the list of file names and can create an array with the path's only using
$lista = #(); foreach ($f in $list) { $lista += $f.Path; }
but can't seem to get any command (del, rm, or Remove-Item) to do anything. Just returns immediately without deleting the files or giving errors.
Thanks
First we can simplify your code as:
Get-ChildItem "*.milk" | Select-String -Pattern "fRating=2" | Select-Object -ExcludeProperty path | Remove-Item -Force -Confirm
The lack of action and errors might be addressable by one of two things. The Force parameter which:
Allows the cmdlet to remove items that cannot otherwise be changed,
such as hidden or read-only files or read-only aliases or variables.
I would aslo suggest that you run this script as administrator. Depending where these files are located you might not have permissions. If this is not the case or does not work please include the error you are getting.
Im going to guess the error is:
remove-item : Cannot remove item C:\temp\somefile.txt: The process cannot access the file 'C:\temp\somefile.txt'
because it is being used by another process.
Update
In testing, I was also getting a similar error. Upon research it looks like the Select-String cmd-let was holding onto the file preventing its deletion. Assumption based on i have never seen Get-ChildItem do this before. The solution in that case would be encase the first part of this in parentheses as a sub expression so it would process all the files before going through the pipe.
(Get-ChildItem | Select-String -Pattern "tes" | Select-Object -ExpandProperty path) | Remove-Item -Force -Confirm
Remove -Confirm if deemed required. It exists as a precaution so that you don't open up a new powershell in c:\windows\system32 and copy paste a remove-item cmdlet in there.
Another Update
[ and ] are wildcard searches in powershell in order to escape those in some cmdlets you use -Literalpath. Also Select-String can return multiple hits in files so we should use -Unique
(Get-ChildItem *.milk | Select-String -Pattern "fRating=2" | Select-Object -ExpandProperty path -Unique) | ForEach-Object{Remove-Item -Force -LiteralPath $_}
Why do you use select-string -pattern "fRating=2"? You would like to select all files with this name?
I think the Format-Table Path don't work. The command Get-ChildItem don't have a property called "Path".
Work this snipped for you?
$list = get-childitem *.milk | Where-Object -FilterScript {$_.Name -match "fRating=2"}
$list | foreach { rm $_.FullName }
The following code gets all files of type *.milk and puts them in $listA, then uses that list to get all the files that contain the string fRating=[01] and stores them in $listB. The files in $listB are deleted and then the number of files deleted versus the number of files that contained the match is displayed(they should be equal).
sv -name listA -value (Get-ChildItem *.milk); sv -name listB -value ($listA | Select-String -Pattern "fRating=[01]"); (($listB | Select-Object -ExpandProperty path) | ForEach-Object {Remove-Item -Force -LiteralPath $_}); (sv -name FCount -value ((Get-ChildItem *.milk).Count)); Write-Host -NoNewline Files Deleted ($listA.Count - $FCount)/($listB.Count)`n;
No need to complicate things:
1. $sourcePath = "\\path\to\the\file\"
2. Remove-Item "$sourcePath*whatever*"
I tried the answer, unfortunately, errors seems to always come up, however, I managed to create a solution to get this done:
Without using Get-ChilItem; You can use select-string directly to search for files matching a certain string, yes, this will return the filename:count:content ... etc, but, internally these have names that you can chose or omit, the one you need is the "filename" to do this pipe this into "select-object" choosing the "FileName" from the output.
So, to select all *.MSG files that has the pattern of "Subject: Webservices restarted", you can do the following:
Select-String -Path .*.MSG -Pattern 'Subject: WebServices Restarted'
-List | select-object Filename
Also, to remove these files on the fly, you could pip into a ForEach statement with the RM command as follows:
Select-String -Path .*.MSG -Pattern 'Subject: WebServices Restarted'
-List | select-object Filename | foreach { rm $_.FileName }
I tried this myself, works 100%.
I hope this helps

Select multiple file types in powershell. Version 2

I am trying to select files that have identical names except for the extenstion...
IE:
idiotCode.dll, idiotCode.pdb, idiotCode.xml, StupidFool.dll, StupidFool.pdb, StupidFool.xml
et cetera.
take a gander at my where-Object call in the below script line...
gci -path $FromPath | ? {$_.Name -match "idiotCode|StupidFool|YourAnIdiot|TheSuckIstHeMatterWhichU" -and $_.Name -like "*.dll"} | foreach{write-host("Do I have the files here? : "+ $_.Fullname + " -destination" + $ToPath) }
Can I use the like parameter to do that? Is there another way to do that? Maybe something in my get-childItem method call which I could pipe into my Where-Object call?
There is a lot that you can do with just the Get-ChildItem Cmdlet. If you look at the help Get-ChildItem, you can do a lot of the filtering there. Specifically using the filters -Filter, -Include and -Exclude
For ex:
Get-ChildItem -Path $FromPath -Include "idiotCode.*","StupidFool.*","YourAnIdiot.*","TheSuckIstHeMatterWhichU.*" -Filter "*.dll"
Ok, I'm a little confused as to the whole concept here because you say you want to select multiple files of the same name but different extensions. Then you pull a directory listing of PathA, filter out everything except files in a kind of "approved names list", and only allow .DLL files to show, and then reference PathB for reasons unknown.
I'm guessing here, but I think you want to query .DLL files from PathA, and then check for matching files from PathB.
$Reference = (GCI $FromPath -Filter "*.DLL").basename
GCI $ToPath|?{$_.BaseName -Match $Reference}|FT -Group BaseName