Format a string of numbers with PowerShell - powershell

I need to take a number such as:
59.234 and make it 00:59.234
and
1:01.555 01:01.555
I need to perform this on a column in a csv file.

If your input csv file looks anything like this:
"Something","Time","MoreStuff"
"whatever","59.234","whereever"
"etcetera","1:01.555","and so forth"
you can use below code to format the time values as you need them:
$csv = Import-Csv -Path 'D:\Test\thefile.csv'
$csv | ForEach-Object {
# get the field to format. in this demo it is $_.Time
$whole, $fraction = ($_.Time -replace '[:,]').PadLeft(8, '0') -split '\.'
# overwrite the field with the formatted time string
$_.Time = '{0}:{1}.{2}' -f $whole.Substring(0,2), $whole.Substring(2,2), $fraction.PadRight(3, '0')
}
# output on screen
$csv
# write to new file
$csv | Export-Csv -Path 'D:\Test\theNewfile.csv' -NoTypeInformation
Output on screen:
Something Time MoreStuff
--------- ---- ---------
whatever 00:59.234 whereever
etcetera 01:01.555 and so forth

This might not be graceful but it might work depending on how the format looks like if you have a smaller or larger number. Eg. 1:59.234 or just 23.
$CSV | select-object #{ Name = "MyTimeSpan"; Expression = { [System.TimeSpan]::Parse(("00:00:" + $_.ColumnName).Substring(("00:00:" + $_.ColumnName).Length - 12,12)) }}

Related

Powershell Select Expanded Property and Custom Expression

I want to get the content of the first value of a specific column using Import-Csv output as a table alongside the name of the file.
I can do:
$File = '\\webserver\Data_20190626.csv'
Import-Csv -Path $File -Delimiter ',' | select 'Effective Date' -First 1
Which gives me my expected output:
Effective Date
--------------
25-May-2019
What I want to see is:
Effective Date FileName
-------------- ---------
25-May-2019 Data_20190626.csv
I have tried this:
$File = '\\webserver\Data_20190626.csv'
Import-Csv -Path $File -Delimiter ',' | select 'Effective Date', #{N='FileName';E={$_.Name}} -First 1
Which resulted in:
Effective Date FileName
-------------- ---------
25-May-2019
How should I proceed?
You can achieve this with Select-Object's property hash table and splitting the file path by \ with the .Split() method. The [-1] indicates the last item in the split result.
$File = '\\webserver\Data_20190626.csv'
Import-Csv -Path $File |
Select-Object 'Effective Date',#{n='FileName';e={$File.Split('\')[-1]}} -First 1
I'm surprised there's no PSPath or anything.
import-csv $file -delimiter ',' |
select 'Effective Date', #{n='Filename';e={split-path -leaf $file}} -first 1
this is a slightly different way to do things. [grin] the #region >>> create a file to work with section can be ignored - it is there to provide the data file you didn't provide.
it gets the EffectiveDate info by using the way that PoSh can dot-address one property of an entire collection and then grabbing the 1st item from the resulting array.
it also avoids the often confusing side effects of allowing spaces or other special chacters in property names by using EffectiveDate instead of Effective Date. if you need to keep using the poorly thot out embedded space, then change that string as needed.
$File = "$env:TEMP\Data_20190626.csv"
#region >>> create a file to work with
#'
EffectiveDate
2019-06-25
2006-06-06
2005-05-05
'# |
ConvertFrom-Csv |
Export-Csv -LiteralPath $File -NoTypeInformation
#endregion >>> create a file to work with
$Results = [PSCustomObject]#{
EffectiveDate = (Import-Csv -LiteralPath $File).EffectiveDate[0]
FileName = $File
}
$Results
output ...
EffectiveDate FileName
------------- --------
2019-06-25 C:\Temp\Data_20190626.csv

Need 3 digits in column in a CSV-file

I have a script that extracts data from an XML file and put this into an CSV file with 2 columns.
The file looks like this:
Name, Count
1,34
3,55
15,66
103,99
etc.
So far so good...
My problem is that the program that reads the CSV-file always expect 3 digits in the column "Name".
So the CSV-file need to look like this:
Name, Count
001,34
003,55
015,66
103,99
etc.
How can I do this formatting using "Export-CSV"?
Please help I'm stuck here..
There are several ways to apply the changes to the csv file.
Read/Import to a variable, change name, Export-Csv variable
$Csv = Import-Csv .\Sample.csv
$Csv | ForEach-Object{ $_.Name = $_.Name.PadLeft(3,'0') }
$Csv | Export-Csv .\NewSample.csv -NoTypeInformation
Do the same on the fly with a calculated property reusing the same header/property name.
Import-Csv .\Sample.csv |
Select-Object #{n='Name';e={$_.Name.PadLeft(3,'0')}},Count|
Export-Csv .\NewSample2.csv -NoTypeInformation
Use the -f ( format ) operator with variable
i.e.
[int] $int = 25;
"{0:D3}" -f $int
Here 3 is a number of digits and Output will be :
025

Powershell script to match string between 2 files and merge

I have 2 files that contain strings, each string in both files is delimited by a colon. Both files share a common string and I want to be able to merge both files (based on the common string) into 1 new file.
Examples:
File1.txt
tom:mioihsdihfsdkjhfsdkjf
dick:khsdkjfhlkjdhfsdfdklj
harry:lkjsdlfkjlksdjfsdlkjs
File2.txt
mioihsdihfsdkjhfsdkjf:test1
lkjsdlfkjlksdjfsdlkjs:test2
khsdkjfhlkjdhfsdfdklj:test3
File3.txt (results should look like this)
tom:mioihsdihfsdkjhfsdkjf:test1
dick:khsdkjfhlkjdhfsdfdklj:test3
harry:lkjsdlfkjlksdjfsdlkjs:test2
$File1 = #"
tom:mioihsdihfsdkjhfsdkjf
dick:khsdkjfhlkjdhfsdfdklj
harry:lkjsdlfkjlksdjfsdlkjs
"#
$File2 = #"
mioihsdihfsdkjhfsdkjf:test1
lkjsdlfkjlksdjfsdlkjs:test2
khsdkjfhlkjdhfsdfdklj:test3
"#
# You are probably going to want to use Import-Csv here
# I am using ConvertFrom-Csv as I have "inlined" the contents of the files in the variables above
$file1_contents = ConvertFrom-Csv -InputObject $File1 -Delimiter ":" -Header name, code # specifying a header as there isn't one provided
$file2_contents = ConvertFrom-Csv -InputObject $File2 -Delimiter ":" -Header code, test
# There are almost certainly better ways to do this... but this does work so... meh.
$results = #()
# Loop over one file finding the matches in the other file
foreach ($row in $file1_contents) {
$matched_row = $file2_contents | Where-Object code -eq $row.code
if ($matched_row) {
# Create a hashtable with the values you want from source and matched rows
$result = #{
name = $row.name
code = $row.code
test = $matched_row.test
}
# Append the matched up row to the final result set
$results += New-Object PSObject -Property $result
}
}
# Convert back to CSV format, with a _specific_ column ordering
# Although you'll probably want to use Export-Csv instead
$results |
Select-Object name, code, test |
ConvertTo-Csv -Delimiter ":"

Convert date format in CSV using PowerShell

I have two CSV file with 50 column and more than 10K row. There is a column having date-time value. In some records it is 01/18/2013 18:16:32 and some records is 16/01/2014 17:32.
What I want to convert the column data like this: 01/18/2013 18:16. I want to remove seconds value. I want to do it by PowerShell script.
Sample data:
10/1/2014 13:18
10/1/2014 13:21
15/01/2014 12:03:19
15/01/2014 17:39:27
15/01/2014 18:29:44
17/01/2014 13:33:59
Since you're not going to convert to a sane date format anyway, you can just do a regex replace of that column:
Import-Csv foo.csv |
ForEach-Object {
$_.Date = $_.Date -replace '(\d+:\d+):\d+', '$1'
} |
Export-Csv -NoTypeInformation foo-new.csv
You could also go the route of using date parsing, but that's probably a bit slower:
Import-Csv foo.csv |
ForEach-Object {
$_.Date = [datetime]::Parse($_.Date).ToString('MM/dd/yyyy HH:mm')
} |
Export-Csv -NoTypeInformation foo-new.csv
If you're sure that there are no other timestamps or anything that could look like it elsewhere, you can also just replace everything that looks like it without even parsing as CSV:
$csv = Get-Content foo.csv -ReadCount 0
$csv = $csv -replace '(\d{2}/\d{2}/\d{4} \d{2}:\d{2}):\d{2}', '$1'
$csv | Out-File foo-new.csv

Powershell import-csv with empty headers

I'm using PowerShell To import a TAB separated file with headers. The generated file has a few empty strings "" on the end of first line of headers. PowerShell fails with an error:
"Cannot process argument because the
value of argument "name" is invalid.
Change the value of the "name"
argument and run the operation again"
because the header's require a name.
I'm wondering if anyone has any ideas on how to manipulate the file to either remove the double quotes or enumerate them with a "1" "2" "3" ... "10" etc.
Ideally I would like to not modify my original file. I was thinking something like this
$fileContents = Get-Content -Path = $tsvFileName
$firstLine = $fileContents[0].ToString().Replace('`t""',"")
$fileContents[0] = $firstLine
Import-Csv $fileContents -Delimiter "`t"
But Import-Csv is expecting $fileContents to be a path. Can I get it to use Content as a source?
You can either provide your own headers and ignore the first line of the csv, or you can use convertfrom-csv on the end like Keith says.
ps> import-csv -Header a,b,c,d,e foo.csv
Now the invalid headers in the file is just a row that you can skip.
-Oisin
If you want to work with strings instead use ConvertFrom-Csv e.g.:
PS> 'FName,LName','John,Doe','Jane,Doe' | ConvertFrom-Csv | Format-Table -Auto
FName LName
----- -----
John Doe
Jane Doe
I ended up needing to handle multiple instances of this issue. Rather than use the -Header and manually setting up each import instance I wrote a more generic method to apply to all of them. I cull out all of the `t"" instances of the first line and save the file to open as a $filename + _bak and import that one.
$fileContents = Get-Content -Path $tsvFileName
if( ([string]$fileContents[0]).ToString().Contains('""') )
{
[string]$fixedFirstLine = $fileContents[0].ToString().Replace('`t""',"")
$fileContents[0] = $fixedFirstLine
$tsvFileName = [string]::Format("{0}_bak",$tsvFileName
$fileContents | Out-File -FilePath $tsvFileName
}
Import-Csv $tsvFileName -Delimiter "`t"
My Solution if you have much columns :
$index=0
$ColumnsName=(Get-Content "C:\temp\yourCSCFile.csv" | select -First 1) -split ";" | %{
$index++
"Header_{0:d5}" -f $index
}
import-csv "C:\temp\yourCSCFile.csvv" -Header $ColumnsName