Use multiple CSVs out a folder individually and save their names - powershell

I have a directory with a lot of .csv Files, and have to do a command with each of them. While I have to do that I also need to save each of their names corresponding to on which file the action is taken. (like when the first file fires, I give out all the content of one .csv file into a txt and want the "title" in the .txt to be the filename)?
Also, I don't want this:
Import-Csv -Path (Get-ChildItem -Path C:\PathToFolder\ -Filter '*.csv').FullName
This code would just give me everything in the CSVs as one, but I want to do something with each of them individually.

Process the output of Get-ChildItem in a loop, e.g.
Get-ChildItem -Path C:\PathToFolder -Filter '*.csv' | ForEach-Object {
Import-Csv $_.FullName | ...
}

Related

Powershell - Extract first line from CSV files and export the results

Thanks in advance for the help.
I have a folder with multiple CSV files. I’d like to be able to extract the first line of each of the files and store the results in a separate CSV file. The newly created CSV file will have the first column as the file name and the second column to be the first line of the file.
The output should look something like this (as an exported CSV File):
FileName,FirstLine
FileName1,Col1,Col2,Col3
FileName2,Col1,Col2,Col3
Notes:
There are other files that should be ignored. I’d like the code to loop through all CSV files which match the name pattern. I’m able to locate the files using the below code:
$targetDir ="C:\CSV_Testing\"
Get-ChildItem -Path $targetDir -Recurse -Filter "em*"
I’m also able to read the first line of one file with the below code:
Get-Content C: \CSV_Testing\testing.csv | Select -First 1
I guess I just need someone to help with looping through the files and exporting the results. Is anyone able to assist?
Thanks
You basically need a loop, to enumerate each file, for this you can use ForEach-Object, then to construct the output you need to instantiate new objects, for that [pscustomobject] is the easiest choice, then Export-Csv will convert those objects into CSV.
$targetDir = "C:\CSV_Testing"
Get-ChildItem -Path $targetDir -Recurse -Filter "em*.csv" | ForEach-Object {
[pscustomobject]#{
FileName = $_.Name
FirstLine = $_ | Get-Content -TotalCount 1
}
} | Export-Csv path\to\theResult.csv -NoTypeInformation
I have assumed the files actually have the .Csv extension hence changed your filter to -Filter "em*.csv", if that's not the case you could use the filter as you currently have it.

Powershell Script that recursively searches for specific file and containing directory and copy it to another location

I'm attempting to write a powershell script that will search recursively for a file and copy it to another location on a local drive with the date appended to it.
However that file could be in multiple different directories. (ex. c:\users\default\Bookmark.txt, c:\users\profile1\Bookmark.txt, c:\users\profile2\Bookmark.txt...etc.)
To distinguish between the different directories I was thinking of appending the directory name containing the file to the filename along with the date. (ex. filename-directoryName-date)
Here is what I have so far:
get-childitem -path "$env:userprofile\AppData\Local\Microsoft\Edge\User Data" -filter Bookmarks -Recurse -ErrorAction SilentlyContinue -Force | copy-item -Destination $env:userprofile\Bookmarks-$(get-date -UFormat %d-%m-%Y)
This works if it only finds 1 copy of the Bookmarks file and it only appends the date.
To figure out the names of the containing folders I used this command.
(get-childitem -path "$env:userprofile\AppData\Local\Microsoft\Edge\User Data" -filter Bookmarks -Recurse -ErrorAction SilentlyContinue -Force).Directory.Name
I need to somehow put this two together and so it outputs :
c:(whateverlocation)\Bookmark-DirectoryName-Date
I hope I'm making sense.
Dan,
When you use the Get-ChildItem command (alias gci) it will return to you an array of DirectoryInfo and FileInfo objects, one for each item it finds. If you are looking for files called "Bookmarks" (or bookmark.txt...can't tell from your examples which one you're looking for) then you can use the following command to get you a list of all of them:
[array]$FileList = gci -Recurse -File -Filter "Bookmarks"
The [array] designation is necessary to be sure the object is an array regardless of how many items are returned. The filter can have wildcards if you don't know the exact filename. What that leaves me with is an array object named $FileList containing all of the information about the files. You can read all about the properties and methods available in these objects at this Microsoft help page.
For this task, we'll need the .FullName property, which tells you the full path & name of each item (which can be used as your source) and the .BaseName & .Extension properties, which give you the filename and extension respectively. Using these properties, you can copy each of the files you find to a destination. Putting it all together, you get something like this:
$SourceFolder = "$($env:userprofile)\AppData\Local\Microsoft\Edge\User Data"
$DestFolder = '' #Path to Destination Folder
[array]$FileList = gci -Path $SourceFolder -Recurse -File -Filter "Bookmarks"
ForEach ($F in $FileList) {
Copy-Item $F.FullName (Join-Path $DestFolder ($F.Name + 'stuff to add to end of filename' + $F.Extension))
}
In this case, since the files are named 'Bookmarks', the $F.Extension should be blank. If using a more traditional filename, the pattern above will help you fit your changes in between the filename and the extension.
Hope this helps you out. If it does, please accept the answer using the check mark on the left.

Renaming Specific Files in various folders with Import-Csv

I’m attempting to rename a bunch of files that are located in multiple folders. The filenames are not unique because they live in multiple directories. Hence, I'd like to fetch all specific files based on their path and then use the Rename-Item cmdlet to make them unique.
I'm using the Import-Csv cmdlet because I have the Paths and New File Names in a text file (headers are oldPath and NewFileName respectively).
I've got this so far:
$documentList = #(Import-Csv -Path 'C:\Users\Desktop\testFolder\fileWithPathAndNewFileName.txt')
$Paths = (ForEach-Object {
(Gci -Path $documentList.oldPath)
})
$Paths | ForEach-Object {Rename-Item -Path $_.FullName -NewName "$($documentlist.newFileName)"}
Unfortunately, this isn't really working, but feels like it's almost there. I think where I'm screwing up is the -NewName parameter. I'm just not sure how to populate the NewFileName object from my text file correctly. Any help would be much appreciated. I apologize in advance if this seems somewhat trivial, I unfortunately haven't been consistent with my Powershell.
Your code is a little confused. ;-) ... if you have CSV file you should name it *.csv.
If I got you right this should be enough actually:
$documentList = Import-Csv -Path 'C:\Users\Desktop\testFolder\fileWithPathAndNewFileName.txt'
foreach ($document in $documentList) {
Rename-Item -Path $document.oldPath -NewName $document.NewFileName
}
You iterate over each row in your CSV file and use the value in the cells as input for the Rename-Item cmdlet. You need to have the complete path including filename to the file in the column "oldPath" and the NewName in the column "NewName"

Powershell - Match ID's in a text file against filenames in multiple folders

I need to search through 350,000 files to find any that contains certain patterns in the filename. However, the list of patterns (id numbers) that it needs to match is 1000! So I would very much like to be able to script this, because they were originally planning on doing it manually...
So to make it clearer:
Check each File in folder and all subfolders.
If the filename contains any of the IDs in the text file then move it to another file
Otherwise, ignore it.
So I have the basic code that works with a single value:
$name = Get-Content 'C:\test\list.txt'
get-childitem -Recurse -path "c:\test\source\" -filter "*$name*" |
move-item -Destination "C:\test\Destination"
If I change $name to point to a single ID, it works, if I have a single ID in the txt file, it works. Multiple items in a list:
1111111
2222222
3333333
It fails. What am I doing wrong? How can I get it to work? I'm still new to powershell so please be a little more descriptive in any answers.
Your test fails because it is effectively trying to do this (using your test data).
Get-ChildItem -Recurse -Path "c:\test\source\" -filter "*1111111 2222222 3333333*"
Which obviously does not work. It is squishing the array into one single space delimited string. You have to account for the multiple id logic in a different way.
I am not sure which of these will perform better so make sure you test both of these with your own data to get a better idea of execution time.
Cycle each "filter"
$filters = Get-Content 'C:\test\list.txt'
# Get the files once
$files = Get-ChildItem -Recurse -Path "c:\test\source" -File
# Cycle Each ID filter manually
$filters | ForEach-Object{
$singleFilter
$files | Where-Object{$_.Name -like "*$singleFilter*"}
} | Move-Item -Destination "C:\test\Destination"
Make one larger filter
$filters = Get-Content 'C:\test\list.txt'
# Build a large regex alternative match pattern. Escape each ID in case there are regex metacharacters.
$regex = ($filters | ForEach-Object{[regex]::Escape($_)}) -join "|"
# Get the files once
Get-ChildItem -Recurse -path "c:\test\source" -File |
Where-Object{$_.Name -match $regex} |
Move-Item -Destination "C:\test\Destination"
try following this tutorial on how to use get-content function. Looks like when you have a multiple line file, you get an array back. you then have to iterate through your array and use the logic you used for only one item

Order of numbered files by get-childitem

I need to change the order by which get-childitem returns the filenames in a directory because it is important to process them in a specific way. The filenames have the following format: f_1.csv, f_2.csv, f_3.csv, f_4.csv, ... , f_10.csv, f_11.csv e.t.c.
The default order that are returned by get-childitem are: f_1.csv, f_10.csv, f_100.csv.
One solution would be to change the filenames to f_001.csv, f_002.csv, f_003.csv but I have no control on how the files were created and I do not know their number (may be hundreds, thousands e.t.c.)
My current code is:
foreach($file in Get-ChildItem $path -Filter f_*.csv)
{
#process the files here
}
Thank you
Something like this?
Get-ChildItem -Filter f_*.csv |
sort #{Expression={[int]($_.name -replace 'f_(\d+).+','$1')};Descending=$false}