powershell / merging .txt-files into csv adding date and filename - powershell

it's me again, as i mentioned yesterday i'm new to Powershell (now 3 days) and i hope you can help me again.
What I want:
I want to merge different txt-files into one csv-file
PLUS every line which is added should start with the actual date (yyyy-mm-dd) and the filename.
Expectation_Image
WhatIamActuallyGetting_Image
So what I've got so far:
New-Item Shoppinglist_$(get-date -f yyyyMMdd_hhmm).csv -ItemType File
$txtFiles = Get-ChildItem -Name *.txt
$desiredColumns = 'Date','Filename','Substance','Information','Comment'
ForEach ($file in $txtFiles) {
$csv = Import-Csv -path $file -Delimiter "`t"
$outcsv=$csv | Select-Object $desiredColumns
#I Think the mistake is somewhere here, but i habe no idea to fix it. :(
Select-Object *, #{Name = 'Date'; Expression = {(Get-Date -format s)}}
Select-Object *, #{Name = 'Filename'; Expression = {(GetFileName)}}
$outcsv | Export-Csv Shoppinglist_$(get-date -f yyyyMMdd_hhmm).csv -NoTypeInformation -Delimiter ";" -Append
}
I hope there is someone outside in the world who can help me. :)

You are right to use calculated properties, but are overthinking this a bit.
Also, Get-ChildItem returns FileInfo or DirectoryInfo objects. (unless you specify switch -Name, in that case it returns only the names of the items in the path).
These objects have useful properties, such as FullName, Name, LastWriteTime, etc.
Since you only want files returned, you can use the -File switch.
This assumes both input files have the exact same columns as in your example:
# the folder where the input files are and where the output csv file should be saved
$path = 'D:\Test'
$today = '{0:yyyy-MM-dd}' -f (Get-Date)
$txtFiles = Get-ChildItem -Path $path -Filter '*.txt' -File
$csv = foreach ($file in $txtFiles) {
Import-Csv -Path $file.FullName -Delimiter "`t" |
Select-Object #{Name = 'Date'; Expression = {$today}},
#{Name = 'Filename'; Expression = {$file.Name}}, *
}
$fileOut = Join-Path -Path $path -ChildPath ('Shoppinglist_{0:yyyyMMdd_HHmm}.csv' -f (Get-Date))
$csv | Export-Csv -Path $fileOut -Delimiter ";" -NoTypeInformation
This assumes both input files have at least the 3 desired columns: 'Substance','Information' and 'Comment'
# the folder where the input files are and where the output csv file should be saved
$path = 'D:\Test'
$today = '{0:yyyy-MM-dd}' -f (Get-Date)
$txtFiles = Get-ChildItem -Path $path -Filter '*.txt' -File
$csv = foreach ($file in $txtFiles) {
Import-Csv -Path $file.FullName -Delimiter "`t" |
Select-Object #{Name = 'Date'; Expression = {$today}},
#{Name = 'Filename'; Expression = {$file.Name}},
Substance, Information, Comment
}
$fileOut = Join-Path -Path $path -ChildPath ('Shoppinglist_{0:yyyyMMdd_HHmm}.csv' -f (Get-Date))
$csv | Export-Csv -Path $fileOut -Delimiter ";" -NoTypeInformation
If you are using a PowerShell version below 3.0, you cannot use the -File switch. Instead then use: $txtFiles = Get-ChildItem -Path $path -Filter '*.txt' | Where-Object { !$_.PSIsContainer }

Related

Powershell split file name and export to csv

I have lot of files in the folder in this nameing format "yyyy-mm-dd_Discription_$Amount.pdf" , how do I make powershell script that creates csv file with three columns (Date , Description and Amount)?
I am able to extract the full file name in the below, but I need help to split and make columns.
$Directory = "C:\path to directory"
Get-ChildItem -Path $Directory -Recurse -Force | ForEach {
[PSCustomObject]#{
Name = $_.BaseName
}
} | Export-Csv -Path "./temp.csv" -NoTypeInformation
I have tried this below
$Directory = "C:\path to directory"
Get-ChildItem -Path $Directory -Recurse -Force | ForEach {
[PSCustomObject]#{
Name = $_.BaseName
}
} | Export-Csv -Path "./temp.csv" -NoTypeInformation
This will work
$Directory = '.'
(Get-ChildItem -Path $Directory -File).BaseName | Select `
#{l='Date'; e={$_.Split('_')[0]}},
#{l='Description'; e={$_.Split('_')[1]}},
#{l='Amount'; e={$_.Split('_')[2]}} |
ConvertTo-Csv -NoTypeInformation

How to make Powershell to output the result to a csv

I am trying to output to a csv file the result that I am getting from "Get-ChildItem"
I need to save only the LastWriteTime and the Name.
This is the Get-ChildItem output
I am trying something like
$pc = Get-WmiObject Win32_ComputerSystem
$file = Get-ChildItem -Path S:\Docker\RCT\repo\*xml -Recurse -Force
$DeviceObj = New-Object PSObject -Property #{
DeviceName = $pc.Name
FileName = $file.Name
FileDate = $file.LastWriteTime
}
$DeviceObjList += $DeviceObj
$DeviceObjList | Export-Csv -Path "$current_path\FileStatus.csv" -NoTypeInformation -Encoding UTF8
But my csv is not saving the file name and also the timestamp
Use a ForEach-Object to loop though your $file object
$pc = Get-WmiObject Win32_ComputerSystem
$file = Get-ChildItem -Path S:\Docker\RCT\repo\*xml -Recurse -Force
$file | ForEach-Object {
$DeviceObj = New-Object PSObject -Property #{
DeviceName = $pc.Name
FileName = $_.Name
FileDate = $_.LastWriteTime
}
$DeviceObjList += $DeviceObj
}
$DeviceObjList | Export-Csv -Path "$current_path\FileStatus.csv" -NoTypeInformation -Encoding UTF8
..but in fact, this is more efficient:
$pc = Get-WmiObject Win32_ComputerSystem
$file = Get-ChildItem -Path S:\Docker\RCT\repo\*xml -Recurse -Force
$DeviceObjList = $file | ForEach-Object {
[pscustomobject]#{
DeviceName = $pc.Name
FileName = $_.Name
FileDate = $_.LastWriteTime
}
}
$DeviceObjList | Export-Csv -Path "$current_path\FileStatus.csv" -NoTypeInformation -Encoding UTF8
You Don't need WMI to get the computer name, use the built-in variable $env:COMPUTERNAME
Use Calculated Properties to add the Computer name to the results.
Iteration not required here, just add the Export-Csv to the pipeline
So you can do that:
$file = Get-ChildItem -Path S:\Docker\RCT\repo\*xml -Recurse -Force
$File | Select #{N="DeviceName";E={$env:COMPUTERNAME}},Name,LastWriteTime |
Export-Csv -Path "$current_path\FileStatus.csv" -NoTypeInformation -Encoding UTF8
And if you want to make it shorter, you can use aliases and don't define any variables
gci S:\Docker\RCT\repo\*xml -R -Fo |
select #{N="DeviceName";E={$env:COMPUTERNAME}},Name,LastWriteTime |
epcsv "$current_path\FileStatus.csv" -NoT -En UTF8

How can I get the time and date my PowerShell script deletes a file

I am using the following script to read a list of file names which are then deleted. Is there a way can get an output of the date and time each file is deleted?
$targetFolder = "D:\" $fileList = "C:\DeleteList.txt" Get-ChildItem
-Path "$targetFolder\*" -Recurse -Include #(Get-Content $fileList) | Remove-Item -Verbose
Thanks for any help.
You could keep track of the files that are deleted and the time of deletion by outputting an object with the file's fullname and current date.
This output can then be saved as structured CSV file
$targetFolder = "D:\"
$fileList = Get-Content -Path "C:\DeleteList.txt"
$deleted = Get-ChildItem -Path $targetFolder -Recurse -Include $fileList | ForEach-Object {
# output an object with the current date and the file FullName
$_ | Select-Object #{Name = 'DeletedOn'; Expression = {(Get-Date)}}, FullName
$_ | Remove-Item -WhatIf
}
# output on screen
$deleted | Format-Table -AutoSize
# output to csv file
$deleted | Export-Csv -Path 'C:\RemovedFiles.csv' -NoTypeInformation
Remove the -WhatIf safety-switch if you are satisfied with the results shown on screen.
Would this work?
$targetFolder = "D:"
$fileList = "C:\DeleteList.txt"
$Files = Get-ChildItem -Path "$targetFolder" -Recurse -Include #(Get-Content $fileList)
# Once you have the desires files stored in the $Files variable, then run a Foreach loop.
$Obj = #() # create an array called $Obj
Foreach ($File in $Files)
{
# store info in hash table
$hash = #{
DateTime = (get-date)
fileName = $File.name
fullpath = $File.fullname
}
Write-Host "deleting file $($file.name)" -for cyan
Remove-Item $File.fullname # *** BE VERY CAREFUL!!!***
# record information in an array called $Obj
$Obj += New-Object psobject -Property $hash
}
$Obj | select fileName, DateTime | Export-csv C:\...

Count the number of files in the directory as well as the number of folders

Currently , I can export the list to a text file and separate them by share name.
My question is : I want to be able to count the number of files in the directory as well as the number of folders into a separate text file.
I'd like to do in this format for text file , $hostname-$sharename-count.txt
For example:
My desired output:
1000 #Folder count
150 #File count
Here is what I have so far:
$outputDir = 'C:\Output'
$Shares = Get-WmiObject Win32_Share -Filter "not name like '%$'"
$re = ($Shares | ForEach-Object {[Regex]::Escape($_.Path)}) -join '|'
foreach ($Share in $Shares) {
$result = (Get-ChildItem -Path $Share.Path -File -Recurse | Select-Object -Expand FullName) -replace "^($re)\\"
# output the results per share in a text file
$fileOut = Join-Path -Path $outputDir -ChildPath ('{0}-{1}.txt' -f $env:COMPUTERNAME, $Share.Name)
$result | Out-File -FilePath $fileOut -Force
}
You can simply expand the code you have like below:
$outputDir = 'C:\Output'
$Shares = Get-WmiObject Win32_Share -Filter "not name like '%$'"
$re = ($Shares | ForEach-Object {[Regex]::Escape($_.Path)}) -join '|'
foreach ($Share in $Shares) {
$files = (Get-ChildItem -Path $Share.Path -File -Recurse | Select-Object -Expand FullName) -replace "^($re)\\"
# output the list of files per share in a text file
$fileOut = Join-Path -Path $outputDir -ChildPath ('{0}-{1}.txt' -f $env:COMPUTERNAME, $Share.Name)
$files | Out-File -FilePath $fileOut -Force
# output the count results for files and folders per share in a text file
$folders = Get-ChildItem -Path $Share.Path -Directory -Recurse
$content = 'Folders: {0}{1}Files: {2}' -f $folders.Count, [Environment]::NewLine, $files.Count
$fileOut = Join-Path -Path $outputDir -ChildPath ('{0}-{1}-count.txt' -f $env:COMPUTERNAME, $Share.Name)
$content | Out-File -FilePath $fileOut -Force
}
P.S. You can add switch -Force to the Get-ChildItem cmdlet to also get the hidden or system files listed if there are any such files inside the shares
If you just want to have a count, you could do something like this:
$resultForFiles = (Get-ChildItem -Path $Share.Path -File -Recurse | Select-Object -Expand FullName)
$resultForFolders = (Get-ChildItem -Path $Share.Path -Directory -Recurse | Select-Object -Expand FullName)
$resultForFiles.Count | Out-File "Path" -Append
$resultForFolders.Count | Out-File "Path" -Append
The -File switch for Get-ChildItem will only get files and the -Directory will only get folders
You can do this in just one line of code
Get-ChildItem | Measure-Object -Property Mode
The property Mode from Get-ChildItem tells you if you are getting folders, files or others.
You can also use get-help Measure-Object -Examples to check some useful examples on measuring files and folders

PowerShell - searching for existing files generates empty output

I wish to search for specific files listed in searchFiles and pipe their locations to TestFileLocation.CSV. However, my current script only generates an empty CSV. What am I missing?
My TestFindFile.csv is of the form:
Name
123.pdf
321.pdf
aaa.pdf
SNIPPET
$searchFiles = Import-CSV 'C:\Data\SCRIPTS\PS1\TestFindFile.csv' -Header ("Name")
$source = 'C:\Data'
ForEach($File in $searchFiles)
{
Get-ChildItem $source -Filter $File -rec | where {!$_.PSIsContainer} | select-object FullName | export-csv -notypeinformation -delimiter '|' -path c:\data\scripts\ps1\TestFileLocation.csv
}
You were overwriting the CSV for each iteration of the loop.
$searchFiles = Import-CSV 'C:\Data\SCRIPTS\PS1\TestFindFile.csv' -Header ("Name")
$source = 'C:\Data'
$outputPath = 'c:\data\scripts\ps1\TestFileLocation.csv'
$searchFiles | ForEach-Object {
# Silently continue to try to ignore error like
# not being able to read path's which are too long
Get-ChildItem $source -Filter $_ -rec -ErrorAction SilentlyContinue | where {!$_.PSIsContainer} | select-object FullName
} | export-csv -notypeinformation -delimiter '|' -path $outputPath
Example using AlphaFS
A comment asked for an example using AlphaFS because it claims to overcome the long path issue. I'm not going into all the details, but here is how I got it to work.
# download and unzip to c:\alpahfs
# dir C:\AlphaFS\* -Recurse -File | Unblock-File
[System.Reflection.Assembly]::LoadFrom('C:\AlphaFS\lib\net451\AlphaFS.dll')
$searchFiles = Import-CSV 'C:\Data\SCRIPTS\PS1\TestFindFile.csv' -Header ("Name")
$source = 'C:\Data'
$outputPath = 'c:\data\scripts\ps1\TestFileLocation.csv'
$searchFiles | ForEach-Object {
$files = [Alphaleonis.Win32.Filesystem.Directory]::EnumerateFiles($source,'*',[System.IO.SearchOption]::AllDirectories)
$files | ForEach-Object { [PSCustomObject] #{FileName = $_} }
} | export-csv -notypeinformation -delimiter '|' -path $outputPath
# type $outputPath
If your .csv file contains the header "Name", there is no need to again declare it when running Import-Csv.
The reason the output is empty is that you are searching for an Object which contains the property Name (imported from the TestFindFile.csv). Search for $File.Name. Also pull commands outside the loop that don't need to be there:
$searchFiles | Select -ExpandProperty Name | % {
Get-ChildItem $source -Filter $_ -Recurse | where {!$_.PSIsContainer}
} | select-object FullName | export-csv -notypeinformation -delimiter '|' -path c:\data\scripts\ps1\TestFileLocation.csv