I'm creating in Excel a sub-folder in a directory and save there multiple CSV-files from a Excel Workbook
My problem is that I need to do this on a system where the list separator is a ','. The CSV files are getting read from a system where the default list separator is a ';'. I cannot change this
So I need to change the ',' in the CSV files into a ';'. My idea is to achieve this using PowerShell.
My first attempt was to change the delimiter of the CSV immediately after creating it in excel by passing to a script the file-name. I manage to change the delimiter for a certain file but I struggle to pass the pathname to the script (no error but also no change in the file):
Script Code:
param([string]$path)
$content = [IO.File]::ReadAllText($path) #readParameter
Import-CSV -Path $content -Delimiter ','|Export-CSV -Path C:\Users\Desktop\temp.csv -Delimiter ';' -NoTypeInformation #Export a CSV-File with ;
(Get-Content C:\Users\Desktop\temp.csv) | % {$_ -replace '"', ""} | out-file -FilePath C:\Users\Desktop\temp.csv -Force -Encoding ascii #remove " from file
Remove-Item -Path $content #remove old CSV-file
Rename-Item -Path C:\Users\Desktop\temp.csv -NewName $content #change file name
Excel Call:
Call Shell("powershell.exe -ExecutionPolicy Unrestricted -File C:\Users\Desktop\delimiterChange.ps1 -path """ & location & """", 1)
Thank You
If you want to use PS, this is the easy quick and dirty. Works like a charm.
$csv = Import-csv "C:\initial.csv"
$csv | Export-Csv "C:\converted.csv" -NoClobber -NoTypeInformation -Delimiter ";"
param([string]$path)
$content = [IO.File]::ReadAllText($path) #readParameter
Import-CSV -Path $content -Delimiter ','|Export-CSV -Path C:\Users\Desktop\temp.csv -Delimiter ';' -NoTypeInformation
Your code reads the content of the CSV (assuming that the path to the CSV is passed via the parameter -Path) and tries to pass that as the path to Import-Csv. Change the above to this:
param([string]$path)
Import-CSV -Path $path |
Export-CSV -Path C:\Users\Desktop\temp.csv -Delimiter ';' -NoType
You can even replace the content of the file if you run Import-Csv in an expression:
(Import-Csv -Path $path) |
Export-Csv -Path $path -Delimiter ';' -NoType
I'd recommend keeping the double quotes, but if you must remove them you can do that in the pipeline like this:
(Import-Csv -Path $path) |
ConvertTo-Csv -Delimiter ';' -NoType |
% { $_ -replace '"', '' } |
Set-Content -Path $path
In Control Panel > Regional Settings > Additional Settings
Set the List Separator to the semi-colon:
Then, in Excel SaveAs CSV
I would take a different approach.
In a Macro enabled Excel workbook:
1) Create a routine which will import a semi-colon-delimited file. It should take a filename as a parameter and return a workbook.
2) Create a routine which will export a workbook as a CSV. It should take a workbook as a parameter, a file name as a parameter, and export/close the workbook
3) Create a routine which reads a file list from the directory and then runs 1) and 2) on each file.
Additionally, I would not name the semi-colon delimited files CSV if you have any control over the original file names. By definition, CSV means Comma Separated Values. Name them something else. Then your routine only has to find the semi-colon files and can skip the CSVs because those have already been converted to comma separated.
Related
Lets say I have a bunch of text files with people's names, that all have this as the content:
number
I want to replace "number" with a value from a CSV or text file, sequentially, and based on the file name. CSV has two columns, name and number:
Joe 5551011000
Gary 5551011001
Clark 5551011002
So I want to find the text file named Joe, and replace the "number" with "5551011000", and the text file named Gary, and replace "number" with "5551011001".
Thank you!
I didn't get too far:
Get-ChildItem "C:\test\*.txt" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace 'changeme', 'MyValue' | Set-Content $_
}
This gets me party there, but I don't know how to find a specific file, then replace "number" in that file with the correct value that matches the name.
I also tried a different approach, with manual entry, and it works, but I need it to just be automated:
get-childitem c:\Marriott -recurse -include *.txt |
select -expand fullname |
foreach {
$new = Read-Host 'What is the new value you want for ' $_
(Get-Content $_) -replace 'number',$new |
Set-Content $_
}
I would convert your CSV to a hashtable, then this gets pretty simple.
$ReplaceHT = #{}
Import-Csv c:\path\to\file.csv -Delimiter ' ' -Header 'FileName','Number' | ForEach-Object {$ReplaceHT.add($_.FileName,$_.Number)}
Get-ChildItem c:\Marriott -recurse -include *.txt -PipelineVariable 'File'|Where{$_.name -in $ReplaceHT.Keys} |ForEach-Object{
(Get-Content $File.FullName) -replace 'changeme', $ReplaceHT[$File.Name] | Set-Content $File.FullName
}
1 .. $Count | ForEach-Object {
$i = $_.ToString($Length)
$Offset = $BatchSize * ($_ - 1)
$outputFile = $ParentDirectory + "\" + $strBaseName + "-" + $i + $strExtension
If($_ -eq 1) {
$objFile | Select-Object -First $BatchSize | Export-Csv $outputFile -NoTypeInformation -Encoding UTF8
} Else {
$objFile | Select-Object -First $BatchSize -Skip $Offset | Export-Csv $outputFile -NoTypeInformation -Encoding UTF8
}
}
I have a .txt with a comma on row 3 below. My code is stripping anything after the comma as seen below. how do I fix it? My file is pipe delimited.
Original file contains
|Header1|Header2|Header3|Header4|
|320|A1| |0900|
|320|A2|This, comma is needed|0900|
|320|A3| |0700|
|320|A4|f2|0900|
|320|A5| |0700|
|320|L2|c6|0900|
After splitting into 2 files -notice the missing text after "this,"
file1
|Header1|Header2|Header3|Header4|
|320|A1| |0900|
|320|A2|This,
|320|A3| |0700|
file2
|Header1|Header2|Header3|Header4|
|320|A4|f2|0900|
|320|A5| |0700|
|320|L2|c6|0900|
Please advise. Thanks
I tried to use delimiter and replace commands. Didn't work
It looks like when you imported your delimited file into $objFile, you forgot to pass -Delimiter '|' to the Import-Csv call, which would not interpret your |-separated file properly, given that Import-Csv - as well as Export-Csv - default to , as the separator.
Thus, the solution is to use -Delimiter '|' in both your Import-Csv and Export-Csv calls.
As for what you tried:
Here's a minimal example that demonstrates the problem with omitting -Delimiter '|', using the in-memory CSV processing cmdlets, ConvertFrom-Csv and ConvertTo-Csv:
#'
Field1|Field2
Value1|Value2, and more
'# |
ConvertFrom-Csv |
ConvertTo-Csv
Output (note the missing , and more part, and how the output lines as a whole are double-quoted):
"Field1|Field2"
"Value1|Value2"
Since header row Field1|Field2 contains no , it became a single property in the resulting objects, literally named Field1|Field2.
Since the data row happened to contain , it was parsed as two fields, and since there is only one column, the extra field was simply discarded.
I want to be able to take a file in a folder and write it to a text file in batch or PowerShell. The output in the text file should have FileName, NewFileName, DateModified. The FileName is what the file was named before it was ingested in a program and output. NewFileName is the name of the file that was output from the program and stored in the output folder.
The PowerShell script below is what I have used to get the name and date modified of the files to display in a text file.
Get-ChildItem -Path D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Audio\ -Recurse |
Select-Object #{n='File'; e={$_.Name + "," + $_.LastWriteTime}} |
Out-File "D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Audio\Log.txt"
Get-ChildItem -Path D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Video\ -Recurse |
Select-Object #{n='File'; e={$_.Name + "," + $_.LastWriteTime}} |
Out-File "D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Video\Log.txt"
However, the output I want is the original file name that was ingested.
FileName before ingested in program: Some_Name_file.mxf
NewFileName after ingested: random_exactly_37_characters_FileName.mxf_random_exactly_11_characters
The original file does not exist anymore, so I could have just added the path of that and said to write its name. So is there a way I can remove those 37 characters before the file name and the last 11 characters at the end of the filename and write that down on the same text file. I do not want to rename the NewFileName because it would change the date modified parameters.
This assumes that the underscores and the file extension are included in what you want to remove, and you always want to remove 37 leading characters and 11 following characters. You can do this using the Substring property of your file name.
$audioFiles = Get-ChildItem -Path D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Audio\ -File -Recurse |
Select-Object #{n='File';e={$_.Name.Substring(37,($_.Name.Length-37-11))}},LastWriteTime
$audioFiles | Export-Csv "D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Audio\Log.csv" -NoTypeInformation
$videoFiles = Get-ChildItem -Path D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Video\ -File -Recurse |
Select-Object #{n='File';e={$_.Name.Substring(37,($_.Name.Length-37-11))}},LastWriteTime
$videoFiles | Export-Csv "D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Video\Log.csv" -NoTypeInformation
Keep in mind that substring character indexes start at 0 and end at Length-1.
An alternative is to use the -replace operator, which uses regex for string matching.
$audioFiles = Get-ChildItem -Path D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Audio\ -File -Recurse |
Select-Object #{n='File';e={$_.Name -replace '^.{37}(.*).{11}$','$1'}},LastWriteTime
$audioFiles | Export-Csv "D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Audio\Log.csv" -NoTypeInformation
$videoFiles = Get-ChildItem -Path D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Video\ -File -Recurse |
Select-Object #{n='File';e={$_.Name -replace '^.{37}(.*).{11}$','$1'}},LastWriteTime
$videoFiles | Export-Csv "D:\Documents\Projects\Trans-Wrapping\TestOut\NewFiles\Video\Log.csv" -NoTypeInformation
The . matches any non-newline character.
{N} matches the previous mechanism (. in this case) N times.
(.*) is a capture group ($1) that matches any character until there are exactly 11 characters left.
^ denotes the beginning of the string.
$ denotes the end of string.
Essentially, the entire filename gets replaced with just the middle substring.
I have a CSV file which looks all fine until it is imported into PowerShell, when its imported each character is followed by a space like C : \ instead of C:\.
It would be easy enough to format the cells to text in Excel (which works) but this CSV file is created on multiple servers by in an automation policy so going through each of these files and formatting them will take a while as you can imagine.
I was wondering if there was a way in which I can format the cells first in PowerShell then import the CSV.
PowerShell code I am using:
$data = import-csv -Path $path -UseCulture -Header #("Path", "Folder", "Size")
CSV Snippet:
C:\,C:\,14.0GB
C:\Program Files,Program Files,4.5GB
C:\Program Files\Microsoft Office,Microsoft Office,2.8GB
It sounds like the file might be Unicode, but without the proper byte order marks, which would cause PowerShell to use the default ASCII encoding. If that is the case, you'll need to specify the encoding:
$data = import-csv -Encoding Unicode -Path $path ...
Another option is to convert the file to ASCII prior to the import [credit to OP for the command]:
Get-content C:\path\TestXml.csv | Set-Content -Encoding Ascii TestXml.csv
this might present a different problem, but it may work for removing all the spaces
$data = import-csv -Path $path -UseCulture -Header #("Path", "Folder", "Size")
$data | % {
$_.path = $_.path -replace '\s'
$_.folder = $_.folder -replace '\s'
$_.size = $_.size -replace '\s'
}
$data
It would be beneficial to get a snippet of what the CSV looks like. Can you provide the header and 1 or 2 rows?
Is the header specified in the CSV file?
When using the Header parameter, delete the original header row from the CSV file. Otherwise, Import-Csv creates an extra object from the items in the header row.
https://technet.microsoft.com/en-us/library/hh849891.aspx
You are specifying the UseCulture switch which will use the default delimiter specified by the environment. You can run the following command to find your culture's delimiter:
(Get-Culture).TextInfo.ListSeparator
https://technet.microsoft.com/en-us/library/hh849891.aspx
#Tony Hinkle sent me in the right direction so I have marked his answer as correct, here is the code that I have used:
Set the content of the CSV to ascii encoding
Get-content C:\Users\sam\Desktop\TestXml.csv | Set-Content -Encoding Ascii TestXml.csv
Then import the Csv
$data = Import-Csv C:\Users\sam\Desktop\TestXml.csv -Header #("Path", "Folder", "Size")
I'm exporting data from multiple paths from our network drives. If a document is older than a certain date, I export it to a CSV file. But when I open up Excel, theres no formatting. Everything is all jammed up in the "A" column. I would like the "Name" to be in column A, "LastWriteTime" to be in column B, etc.
Here is my code:
foreach($path in $SharedFolder)
{
Get-ChildItem -Path $path -Recurse | Where-Object {!$_.PSIsContainer -and $_.LastWriteTime -lt $DateLimit} |
Select-Object Name, LastWriteTime, LastAccessTime, Length, DirectoryName |
Export-Csv -Path $HOME\Desktop\ExcelDoc.csv -NoTypeInformation
}
Any help would be appreciated.
Setting the delimiter to the system default delimiter should take care of this.
You can do this by adding -Delimiter to your command with the character specified.
For example: -Delimiter ';'