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

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.

Related

How can I add a line break for every tilde found within the contents of several files found at a path?

I would like to use PowerShell to add a line break for every tilde it finds in a file.
The source could contain main .in files which contain tildes.
I have this script so far, and could benefit by some assistance in how to tweak it.
This will work for one file, but not for many:
(Get-Content -Path '.\amalgamatedack.in') |
ForEach-Object {$_.Replace('~', "~`r`n")} |
Set-Content -Path '.\amalgamatedack.in'
You can use Get-ChildItem to find all your .in files, then follow the same logic, just replace the input and output hardcoded file name for the absolute path of each file (.FullName property).
Your code could also benefit by using Get-Content -Raw, assuming these files are not very big and they fit in memory, reading the content as single multi-line string is always faster.
# If you need to search recursively for the files use `-Recurse`
Get-ChildItem path\to\sourcefolder -Filter *.in | ForEach-Object {
($_ | Get-Content -Raw).Replace('~', "~`r`n") |
Set-Content -Path $_.FullName
}

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"

Use multiple CSVs out a folder individually and save their names

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 | ...
}

Copying files defined in a list from network location

I'm trying to teach myself enough powershell or batch programming to figure out to achieve the following (I've had a search and looked through a couple hours of Youtube tutorials but can't quite piece it all together to figure out what I need - I don't get Tokens, for example, but they seem necessary in the For loop). Also, not sure if the below is best achieved by robocopy or xcopy.
Task:
Define a list of files to retrieve in a csv (file name will be listed as a 13 digit number, extension will be UNKNOWN, but will usually be .jpg but might occasionally be .png - could this be achieved with a wildcard?)
list would read something like:
9780761189931
9780761189988
9781579657159
For each line in this text file, do:
Search a network folder and all subfolders
If exact filename is found, copy to an arbitrary target (say a new folder created on desktop)
(Not 100% necessary, but nice to have) Once the For loop has completed, output a list of files copied into a text file in the newly created destination folder
I gather that I'll maybe need to do a couple of things first, like define variables for the source and destination folders? I found the below elsewhere but couldn't quite get my head around it.
set src_folder=O:\2017\By_Month\Covers
set dst_folder=c:\Users\%USERNAME&\Desktop\GetCovers
for /f "tokens=*" %%i in (ISBN.txt) DO (
xcopy /K "%src_folder%\%%i" "%dst_folder%"
)
Thanks in advance!
This solution is in powershell, by the way.
To get all subfiles of a folder, use Get-ChildItem and the pipeline, and you can then compare the name to the insides of your CSV (which you can get using import-CSV, by the way).
Get-ChildItem -path $src_folder -recurse | foreach{$_.fullname}
I'd personally then use a function to edit the name as a string, but I know this probably isn't the best way to do it. Create a function outside of the pipeline, and have it return a modified path in such a way that you can continue the previous line like this:
Get-ChildItem -path $src_folder -recurse | foreach{$_.CopyTo (edit-path $_.fullname)}
Where "edit-directory" is your function that takes in the path, and modifies it to return your destination path. Also, you can alternatively use robocopy or xcopy instead of CopyTo, but Copy-Item is a powershell native and doesn't require much string manipulation (which in my experience, the less, the better).
Edit: Here's a function that could do the trick:
function edit-path{
Param([string] $path)
$modified_path = $dst_folder + "\"
$modified_path = $path.substring($src_folder.length)
return $modified_path
}
Edit: Here's how to integrate the importing from CSV, so that the copy only happens to files that are written in the CSV (which I had left out, oops):
$csv = import-csv $CSV_path
Get-ChildItem -path $src_folder -recurse | where-object{$csv -contains $_.name} | foreach{$_.CopyTo (edit-path $_.fullname)}
Note that you have to put the whole CSV path in the $CSV_path variable, and depending on how the contents of that file are written, you may have to use $_.fullname, or other parameters.
This seems like an average enough problem:
$Arr = Import-CSV -Path $CSVPath
Get-ChildItem -Path $Folder -Recurse |
Where-Object -FilterScript { $Arr -contains $PSItem.Name.Substring(0,($PSItem.Length - 4)) } |
ForEach-Object -Process {
Copy-Item -Destination $env:UserProfile\Desktop
$PSItem.Name | Out-File -FilePath $env:UserProfile\Desktop\Results.txt -Append
}
I'm not great with string manipulation so the string bit is a bit confusing, but here's everything spelled out.

Append filename to CSV in new column

I have a lot of csv files stored in a directory.
In each csv file need to add the name as column this through powershell.
Example
File location: <SERVERNAME>\Export\FILENAME1.CSV
Contents:
1232;Description;a1
1232;Description;a2
The result must be:
1232;Description;a1;FILENAME1.CSV
1232;Description;a2;FILENAME1.CSV
Can someone help me with this?
The following will append a Filename column to each .CSV file in a directory:
Get-ChildItem *.csv | ForEach-Object {
$CSV = Import-CSV -Path $_.FullName -Delimiter ";"
$FileName = $_.Name
$CSV | Select-Object *,#{N='Filename';E={$FileName}} | Export-CSV $_.FullName -NTI -Delimiter ";"
}
Explanation:
Uses Get-ChildItem to get all files named *.csv
Iterates through each file with ForEach-Object and uses Import-CSV to load their contents as a PowerShell object
Records the name of the file in $FileName
Uses Select-Object to add a calculated property with the name Filename and the value of the $FileName variable
Uses Export-CSV to write back over the original file. The -NTI (NoTypeInformation) switch is used to ensure the PowerShell object header line is not included.
Mark Wragg's PowerShell code works, but I had to change the delimiter to , instead of ; so that it opens in Excel. I'm trying to figure out how to append the filename to the first column instead of the last because my files don't have the same number of fields so they don't align.