UPDATE
I have got a log file of 1000 lines containing some reference.
Time Reference Date of start Date of end
12:00 AT001 13 November 2011 15 November 2011
13:00 AT038 15 December 2012 17 December 2012
14:00 AT076 17 January 2013 19 January 2013
$ref1 = AT038
Basically, I want to parse the log file and have an output (line by line) for $ref1 such as :
Time : 13h
Reference : AT038
Date of start : 15 December 2012
Date of end : 17 December 2012
Thanks in advance
try:
$ref1 = "AT038"
$csv = Import-Csv .\myfile.txt -Delimiter ' '#Import file as CSV with space as delimiter
$csv | ? { $_.reference -EQ $ref1 } | FL #Piping each line of CSV to where-object cmdlet, filtering only line where value of column reference is equal to $ref1 variable value. Piping the result of the filtering to file-list to have output as requested in OP.
Code added after requisite are changed in OP:
$ref1 = "AT038"
$txt = gc .\myfile.txt
$txt2 = $txt | % { $b = $_ -split ' '; "$($b[0]) $($b[1]) $($b[2])_$($b[3])_$($b[4]) $($b[5])_$($b[6])_$($b[7])" }
$csv = convertfrom-csv -InputObject $txt2 -Delimiter ' '
$csv | ? { $_.reference -EQ $ref1 } | FL
How about this:
Get-Content SourceFileName.txt |
% { ($_ -Replace '(\d{2}):\d{2} (\w{2}\d{3})', 'Time : $1h|Reference : $2').Split('|')} |
Out-File TargetFileName.txt
Here is my revised version:
$regex = '(\d{2}):\d{2} (\w{2}\d{3}) (\d{2} \b\w+\b \d{4}) (\d{2} \b\w+\b \d{4})'
$replace = 'Time : $1h|Reference : $2|Date of start : $3|Date of end : $4'
Get-Content SourceFileName.txt |
% { ($_ -Replace $regex, $replace).Split('|')} |
Out-File TargetFileName.txt
Related
I am trying to write a script to take a bunch of text files in a folder (which are all in the same format) and output them to a csv file. Each file has the same "header" information. I have been able to get information in a more easily usable format (removing the first and last lines, which aren't needed), but am having some trouble after that.
Here is the beginning of the text file, though there will be more than just these 7 lines, there will be a total of 36 lines per file:
TYPE VOID
DOB 20200131
DATE 20200131
TIME 21:19:42
TERMINAL 3
ORGTERM 2
EMPLOYEE 1234 John Doe
And here is what I have so far, though I know that it doesn't work:
$currentdir = '.\'
$results = #()
$outputfilename = 'data.csv'
foreach ($req in Get-ChildItem($currentdir)) {
(Get-Content $req)[1..((Get-Content $req).count - 2)] |
ForEach-Object {
$header = $_[0] -split '`t'
$data = $_[1] -split '`t'
$results = $header, $data
}
}
The final product would look something like this:
A B C D E F G
1 TYPE DOB DATE TIME TERMINAL ORGTERM EMPLOYEE
2 VOID 20200131 20200131 21:19:42 3 2 1234 John Doe
3 AUTHORIZE 20200131 20200131 23:29:22 2 4678 Jane Doe
Full sample of VOID file:
BEGIN
TYPE VOID
DOB 20200131
DATE 20200131
TIME 21:19:42
TERMINAL 3
ORGTERM 2
EMPLOYEE 1234 Jane Doe
TABLE TBL 101
CHECK 20030
PAYMENT 20029
AUTHAMT 20.68
BATCHAMT 20.68
CARDTYPE MASTERCARD
CARDMASK XXXXXXXXXXXXXXXXX
{XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}
EXP 0423
REF 482
STANDALONE YES
PINDEX 1
APPROVEAMT 20.68
LOGTIME 21:07:01
FOHFEATS 10000000000000000000000000000000
TERMCAPS 00000000000000000000000000000000
FOHVERSION 15.1.34.2.97
ACTIONCODE 000
LASTSEND 1580585993
ORIGDATE 20200131
ORIGTIME 21:02:11
ORIGTYPE AUTHORIZE
ORIGREF 482
ORGREFTIME 21:02:11
TENDER_NUM 12
CRCY 840
VPD Sequence #: 107
REVID 2
REVNAME 712 Bar
END
Sample AUTHORIZE file:
BEGIN
TYPE AUTHORIZE
DOB 20200131
DATE 20200131
TIME 23:29:22
TERMINAL 2
EMPLOYEE 1234 Jane Doe
TABLE Table 121
CHECK 20045
PAYMENT 20038
AUTHAMT 72.42
BATCHAMT 72.42
CARDTYPE VISA
CARDMASK XXXXXXXXXXXXXXXX
{XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}
EXP 0124
REF 485900
STANDALONE YES
PINDEX 1
LOGTIME 23:29:22
FOHFEATS 10000000000000000000000000000000
TERMCAPS 00000000000000000000000000000000
FOHVERSION 15.1.34.2.97
LASTSEND 1580586235
TENDER_NUM 13
CRCY 840
REVID 1
REVNAME 712 Restaurant
COMMERROR TRUE
END
Sample adjust file:
BEGIN
TYPE ADJUST
DOB 20200131
DATE 20200131
TIME 22:18:27
TERMINAL 8
ORGTERM 8
EMPLOYEE 789 Judy Garland
TABLE BAR GUEST
CHECK 80161
PAYMENT 80036
BATCHAMT 30.43
BATCHTIP 6
CARDTYPE MASTERCARD
CARDMASK XXXXXXXXXXXX8699
{XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}
EXP 0323
REF 1504602
STANDALONE YES
PINDEX 1
LOGTIME 22:18:27
FOHFEATS 10000000000000000000000000000000
TERMCAPS 00000000000000000000000000000000
FOHVERSION 15.1.34.2.97
LASTSEND 1580638928
TENDER_NUM 12
CRCY 840
REVID 4
REVNAME 712 Second Bar
END
here's one way to merge those text files into a CSV. it presumes the files are in a specific dir and can be loaded by matching the names OR by simply grabbing all the files.
what it does ...
sets the source dir
sets the file filter
grabs all the matching files
iterates thru the file list
loads each file into a $Var
uses the way that PoSh handles a collection on the LEFT side of a match
that gives you the matching item, not the usual [bool].
builds a PSCustomObject
it does that by matching the line with the target word, getting the 1st item in the returned array, replaces the unwanted part of the line with nothing, and finally assigns that value to the desired property.
this is rather inefficient, but i can't think of a better way. [blush]
sends the PSCO out to the $Results collection
shows what is in $Results on the screen
exports $Results to a CSV file
here's the code ...
$SourceDir = $env:TEMP
$Filter = 'harlan_*.txt'
$FileList = Get-ChildItem -LiteralPath $SourceDir -Filter $Filter -File
$Results = foreach ($FL_Item in $FileList)
{
$Lines = Get-Content -LiteralPath $FL_Item.FullName
[PSCustomObject]#{
Type = ($Lines -match '^type')[0] -replace '^type\s{1,}'
DOB = ($Lines -match '^dob')[0] -replace '^dob\s{1,}'
Date = ($Lines -match '^date')[0] -replace '^date\s{1,}'
Time = ($Lines -match '^time')[0] -replace '^time\s{1,}'
Terminal = ($Lines -match '^terminal')[0] -replace '^terminal\s{1,}'
OrgTerm = ($Lines -match '^orgterm')[0] -replace '^orgterm\s{1,}'
Employee = ($Lines -match '^employee')[0] -replace '^employee\s{1,}'
}
}
# show on screen
$Results
# save to CSV
$Results |
Export-Csv -LiteralPath "$SourceDir\Harlan_-_MergedFiles.csv" -NoTypeInformation
display on screen ...
Type : ADJUST
DOB : 20200131
Date : 20200131
Time : 22:18:27
Terminal : 8
OrgTerm : 8
Employee : 789 Judy Garland
Type : AUTHORIZE
DOB : 20200131
Date : 20200131
Time : 23:29:22
Terminal : 2
OrgTerm :
Employee : 1234 Jane Doe
Type : VOID
DOB : 20200131
Date : 20200131
Time : 21:19:42
Terminal : 3
OrgTerm : 2
Employee : 1234 Jane Doe
content of the csv file ...
"Type","DOB","Date","Time","Terminal","OrgTerm","Employee"
"ADJUST","20200131","20200131","22:18:27","8","8","789 Judy Garland"
"AUTHORIZE","20200131","20200131","23:29:22","2","","1234 Jane Doe"
"VOID","20200131","20200131","21:19:42","3","2","1234 Jane Doe"
To capture all fields in the files without hardcoding the headers and combine them into a CSV file, the below code should do it.
Snag is that there is one line in each file that does not have a 'Header', it is just a string {XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}.
I'm guessing that should be the Card Number, so I'm manually inserting the header CARDNUMBER there. If this is something else, please change that in the code.
$files = Get-ChildItem -Path 'D:\Test' -File
$result = foreach($file in $files) {
$obj = [PsCustomObject]#{}
Get-Content -Path $file.FullName | Where-Object { $_ -notmatch '^(BEGIN|END)$' } | ForEach-Object {
# There is a line without 'header' name. Is this the card number?
if ($_ -like '{*}') {
$name = 'CARDNUMBER' # <-- add your own preferred header name here
$value = $_
}
else {
$name,$value = $_ -split '\s+', 2
}
$obj | Add-Member -MemberType NoteProperty -Name $name -Value $value
}
# output the object for this file to be colected in the $result variable
$obj
}
# output on screen
$result
#output to CSV file
$result | Export-Csv -Path 'D:\output.csv' -NoTypeInformation
You need to set the paths for Get-ChildItem and Export-CSV to match your own situation of course
If I'm reading this correctly you have some files each has a single record of data delimited between the aptly positions words "BEGIN" & "END" You want each file to be translated into a single CSV file?
I think I've cooked up something worth while. Though I'm sure it's not perfect.
$Select = 'TYPE','DOB','DATE','TIME','TERMINAL','ORGTERM','EMPLOYEE'
ForEach( $InputFile in (Get-ChildItem $CurrentDirectory) )
{
$OutputFile = $InputFile.BaseName + '.csv'
$Table = Get-Content $InputFile
$TempHash = [Ordered]#{}
ForEach( $Column in $Table )
{
If( $Column -notmatch '(^BEGIN$|^END$)' )
{
$TempArr = $Column.Split( ' ', 2, [System.StringSplitOptions]::RemoveEmptyEntries ) | ForEach{$_.Trim()}
If( $Select -contains $TempArr[0] )
{
$TempHash.Add($TempArr[0], $TempArr[1] )
}
}
}
#Now $TempHash should have enough to create the object and export to CSV
[PSCustomObject]$TempHash | Export-Csv -Path $OutputFile -NoTypeInformation
}
A few points:
I'm ignoring the lines BEGIN & END
I'm manipulating each line thereafter into an array, which for the
most part should be 2 elements.
If the first element [0] is in the collection of fileds your looking
for I'll add as a key/value pair to the hash. Otherwise do nothing.
After processing the lines Convert the object to a PSCustomObject and
export to a CSV file.
I only tested it on a single file I created from your question. I wrapped up the outer loop just as pseudo code.
This works, but the output looks a little choppy, like numbers being strings and such. That said, as a rev one I think we've got something to work with.
If misread your comment, and you want a single output CSV file the adjustment is just to declare the filename before the loop and use the append param on the Export-CSV cmdlet. See below, though I didn't test it any further:
$OutputFile = 'YourOutput.csv'
$Select = 'TYPE','DOB','DATE','TIME','TERMINAL','ORGTERM','EMPLOYEE'
ForEach( $InputFile in (Get-ChildItem $CurrentDirectory) )
{
$Table = Get-Content $InputFile
$TempHash = [Ordered]#{}
ForEach( $Column in $Table )
{
If( $Column -notmatch '(^BEGIN$|^END$)' )
{
$TempArr = $Column.Split( ' ', 2, [System.StringSplitOptions]::RemoveEmptyEntries ) | ForEach{$_.Trim()}
If( $Select -contains $TempArr[0] )
{
$TempHash.Add($TempArr[0], $TempArr[1] )
}
}
}
#Now $TempHash should have enough to create the object and export to CSV
[PSCustomObject]$TempHash | Export-Csv -Path $OutputFile -NoTypeInformation -Append
}
Sorry about the variable names, that could obviously use a refactor...
Let me know what you think.
I found a similar post regarding the problem in the link below.
How to fetch first column from given powershell array?
I am not able to directly convert it to a table as some fields are missing and do operations.
Customer ID Client Name Computer Name Computer Brand Duration Connection Time Lang
123 first last 127.0.0.1 lenovo 10:00 8/18/2019 6:00 PM Eng
1 lastname 127.0.0.2 apple 2:30:00 8/18/2019 1:00 AM Chn
86 user3 127.0.0.1 dell 8/18/2019 2:00 PM
21 user4 127.0.0.4 apple 30:00 8/17/2019 1:00 PM Eng
I want to first filter with a specific user who is connected for more than 30 minutes and then list its id.
Update
The result should be
1
21
because they are connected for 30min and over.
If the data you show is indeed the output of a Fixed-Width file, you need to try and get the widths for each field in order to parse it. A handicap here is that the original header names contain a space character and we need to replace that by an underscore.
For that, you can use the below function:
function ConvertFrom-FixedWith {
[CmdletBinding()]
Param(
[Parameter(Mandatory = $true, Position = 0)]
[string[]]$Content
)
$splitter = '§¤¶' # some unlikely string: Alt-21, [char]164, Alt-20
$needQuotes = '^\s+|[",]|\s+$' # quote the fields if needed
function _FWClean ([string]$field) {
# internal helper function to clean a field value with regards to quoted fields
$field = $_.Trim() -replace '(?<!\\)\\"|""', '§DQUOTE¶'
if ($field -match '^"(.*)"$') { $field = $matches[1] }
if ($field -match $needQuotes) { $field = '"{0}"' -f $field }
return $field -replace '§DQUOTE¶', '""'
}
# try and calculate the field widths using the first header line
# this only works if none of the header names have spaces in them
# and where the headers are separated by at least one space character.
Write-Verbose "Calculating column widths using first row"
$row = ($Content[0] -replace '\s+', ' ').Trim()
$fields = #($row -split ' ' ) # | ForEach-Object { _FWClean $_ })
$ColumnBreaks = for ($i = 1; $i -lt $fields.Length; $i++) {
$Content[0].IndexOf($fields[$i])
}
$ColumnBreaks = $ColumnBreaks | Sort-Object -Descending
Write-Verbose "Splitting fields and generating output"
$Content | ForEach-Object {
if ($null -ne $_ -and $_ -match '\S') {
$line = $_
# make sure lines that are too short get padded on the right
if ($line.Length -le $ColumnBreaks[0]) { $line = $line.PadRight(($ColumnBreaks[0] + 1), ' ') }
# add the splitter string on every column break point
$ColumnBreaks | ForEach-Object {
$line = $line.Insert($_, $splitter)
}
# split on the splitter string, trim, and dedupe possible quotes
# then join using the delimiter character
#($line -split $splitter | ForEach-Object { _FWClean $_ }) -join ','
}
} | ConvertFrom-Csv # the result is an array of PSCustomObjects
}
With that function in place, parsing the text can be done like so:
$text = #"
Customer_ID Client_Name Computer_Name Computer_Brand Duration Connection_Time Lang
123 first last 127.0.0.1 lenovo 10:00 8/18/2019 6:00 PM Eng
1 lastname 127.0.0.2 apple 2:30:00 8/18/2019 1:00 AM Chn
86 user3 127.0.0.1 dell 8/18/2019 2:00 PM
21 user4 127.0.0.4 apple 30:00 8/17/2019 1:00 PM Eng
"# -split '\r?\n'
# replace the single space characters in the header names by underscore
$text[0] = $text[0] -replace '(\w+) (\w+)', '$1_$2'
# the 'ConvertFrom-FixedWith' function takes a string array as input
$table = ConvertFrom-FixedWith -Content $text
#output on screen
$table | Format-Table -AutoSize
# export to CSV file
$table | Export-Csv -Path 'D:\test.csv' -NoTypeInformation
Output (on screen)
Customer ID Client Name Computer Name Computer Brand Duration Connection Time Lang
----------- ----------- ------------- -------------- -------- --------------- ----
123 first last 127.0.0.1 lenovo 10:00 8/18/2019 6:00 PM Eng
1 lastname 127.0.0.2 apple 2:30:00 8/18/2019 1:00 AM Chn
86 user3 127.0.0.1 dell 8/18/2019 2:00 PM
21 user4 127.0.0.4 apple 30:00 8/17/2019 1:00 PM Eng
If your input $text is already a string array storing all the ines as we see them in your question, then leave out the -split '\r?\n'
Having parsed the input to a table of PsCustomObjects, you can get the customers that are connected for 30 minutes or more with the help of another small helper function:
function Get-DurationInMinutes ([string]$Duration) {
$h, $m, $s = (('0:{0}' -f $Duration) -split ':' | Select-Object -Last 3)
return [int]$h * 60 + [int]$m
}
($table | Where-Object { (Get-DurationInMinutes $_.Duration) -ge 30 }).Customer_ID
This will output
1
21
Update
Now that we finally know the data is from a TAB delimited CSV file, you don't need the ConvertFrom-FixedWith function.
Simply import the data using if it comes from a file
$table = Import-Csv -Path 'D:\customers.csv' -Delimiter "`t"
Or, if it comes from the output of another command as string or string array:
$table = $original_output | ConvertFrom-Csv -Delimiter "`t"
Then, use the Get-DurationInMinutes helper function just like above to get the Customer ID's that are connected for more than 30 minutes:
function Get-DurationInMinutes ([string]$Duration) {
$h, $m, $s = (('0:{0}' -f $Duration) -split ':' | Select-Object -Last 3)
return [int]$h * 60 + [int]$m
}
($table | Where-Object { (Get-DurationInMinutes $_.Duration) -ge 30 }).'Customer ID'
Uhh. I'm surprised there's not a canonical way to do this. Based on https://www.reddit.com/r/PowerShell/comments/211ewa/how_to_convert_fixedwidth_to_pipedelimited_or/.
# 0 19 38 59 81 97 120 123
# Customer ID Client Name Computer Name Computer Brand Duration Connection Time Lang
# 123 first last 127.0.0.1 lenovo 10:00 8/18/2019 6:00 PM Eng
# 1 lastname 127.0.0.2 apple 2:30:00 8/18/2019 1:00 AM Chn
# 86 user3 127.0.0.1 dell 8/18/2019 2:00 PM
# 21 user4 127.0.0.4 apple 30:00 8/17/2019 1:00 PM Eng
$cols = 0,19,38,59,81,97,120,123 # fake extra column at the end, assumes all rows are that wide
$firstline = get-content columns.txt | select -first 1
$headers = for ($i = 0; $i -lt $cols.count - 1; $i++) {
$firstline.substring($cols[$i], $cols[$i+1]-$cols[$i]).trim()
}
# string Substring(int startIndex, int length)
$lines = Get-Content columns.txt | select -skip 1
$lines | ForEach {
$hash = [ordered]#{}
for ($i = 0; $i -lt $headers.length; $i++) {
$hash += #{$headers[$i] = $_.substring($cols[$i], $cols[$i+1]-$cols[$i]).trim()}
}
[pscustomobject]$hash
}
Output:
PS /Users/js/foo> ./columns | ft
Customer ID Client Name Computer Name Computer Brand Duration Connection Time Lan
----------- ----------- ------------- -------------- -------- --------------- ---
123 first last 127.0.0.1 lenovo 10:00 8/18/2019 6:00 PM Eng
1 lastname 127.0.0.2 apple 2:30:00 8/18/2019 1:00 AM Chn
86 user3 127.0.0.1 dell 8/18/2019 2:00 PM
21 user4 127.0.0.4 apple 30:00 8/17/2019 1:00 PM Eng
I think you have a couple of requirements here. I'm going to describe one way to do it using a generic 'for loop' and regular expression - something you can play with and tweak to your needs. There are better ways of doing this (Powershell shortcuts), but based on the way you asked I'm going to assume that understanding is your goal, so this code should serve well if you have a background in any programming language. Hope this helps!
# Here is your data formatted in an array. Missing values are just empty fields.
# You could have fewer or more fields, but I've broken up your data into nine fields
# (0-8 when counting elements in an array)
# Customer ID, FName, LName, ComputerHostName, Brand, Duration, ConnectionDate, ConnectionTime, Lang
$myarray = #(
('123', 'firstname', 'lastname', '127.0.0.1', 'lenovo', '10:00', '8/18/2019', '6:00 PM', 'Eng'),
('1', 'lastnam', '', '127.0.0.2', 'apple', '2:30:00', '8/18/2019', '1:00 AM', 'Chn'),
('86', 'user3', '', '127.0.0.1', 'dell', '04:33', '8/18/2019', '2:00 PM', ''),
('21', 'user4', '', '127.0.0.4', 'apple', '30:00', '8/17/2019', '1:00 PM', 'Eng')
)
# This is a generic for loop that prints the ComputerHostName, which is the 4th column.
# The 4th column is column #3 if counting from zero (0,1,2,3)
# I'm using a regular expression to match duration above 30 minutes with the '-match' operator
for ( $i = 0; $i -lt $myarray.Length; $i++ ) {
if ( $myarray[$i][5] -match "[3-5][0-9]:[0-9][0-9]$" ){
"$($myarray[$i][5]) - $($myarray[$i][3])"
}
}
Printed Result:
2:30:00 - 127.0.0.2
30:00 - 127.0.0.4
I am trying to use the Format-Table command to output an array of hash tables of all files checked out from our TFS repo.
My code thus far:
$arr = #();
#Take the string from the tf command, parse it and build an array of hash tables
(tf stat /recursive /user:* /format:detailed | Select-String -Pattern '^\$' -NotMatch | Select -SkipLast 3 | Out-String) -split '(\r\n){2}' | ForEach-Object {
$ht = #{};
if ($_ -ne '') {
$str = $_ | Out-String;
$str -split '\r?\n'| ForEach-Object {
$key, $value = $_ -split '\s*:\s*';
#Write-Host $key, $Value;
try {
$ht.Add($key, $value);
} catch [ArgumentException] {
Write-Host "Caught exception";
}
}
$arr += ($ht);
}
}
Edit
Looks like I'm erroring out here.
$arr.ForEach({[PSCustomObject]$_}) | Format-Table -AutoSize
Full Error:
Cannot convert value "System.Collections.Hashtable" to type
"System.Management.Automation.LanguagePrimitives+InternalPSCustomObject". Error: "Cannot process argument because the
value of argument "name" is not valid. Change the value of the "name" argument and run the operation again."
At C:\Dev\Tools\powershell\Convert-TfsOutput.ps1:21 char:15
+ $arr.ForEach({[PSCustomObject]$_}) | Format-Table -AutoSize
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastConstructorException
Edit2
Here is sample output when i replace the above line with:
$arr.ForEach({ $_ | Out-String })
Name Value
---- -----
Workspace work1
Date {Wednesday, September 5, 2018 1, 38, 48 PM}
Local item file1
File type Windows-1252
User user1
Lock none
Change edit
Name Value
---- -----
Workspace work2
Date {Monday, September 10, 2018 12, 14, 56 PM}
Local item file2
User user2
Lock none
Change edit
Edit 3
Output of the below command
Write-Host $str;
User : User1
Date : Wednesday, September 5, 2018 1:38:48 PM
Lock : none
Change : edit
Workspace : Work1
Local item : File1
File type : Windows-1252
User : User2
Date : Monday, September 10, 2018 12:14:56 PM
Lock : none
Change : edit
Workspace : Work2
Local item : File2
Would like the output in a tabular format with rows below the column names:
Workspace | Date | Local item | File type | User | Lock | Change
Tried to use the code in another answer but it does not output correctly.
Format-Table on Array of Hash Tables
Convert your hashtables to custom objects before passing them to Format-Table.
... | Where-Object { $_ } | ForEach-Object {
$ht = #{};
($_ | Out-String) -split '\r?\n'| ForEach-Object {
...
}
New-Object -Type PSObject -Property $ht
} | Format-Table
Edit: Looks like your input data has blank lines which lead to keys with empty strings in your hashtables, which then cause the error you observed, because objects can't have a property with an empty string for a name.
Change your hashtable/object creation to something like this:
... | Where-Object { $_ } | ForEach-Object {
$ht = ($_ | Out-String).Trim() -replace '\s+:\s+', '=' |
ConvertFrom-StringData
New-Object -Type PSObject -Property $ht
} | Format-Table
Trying to add a line break here but it's not working. Tried also using the `r, but no luck.
My code:
$extract = #()
Select-String -Path $outfile -Pattern "text" -Context 0,12 |
ForEach-Object {
$extract += $_.Line | foreach {$_.Replace("text", "DD/MM")}
$extract += $_.Context.PostContext | foreach {$_.Replace(',', "`n")}
}
$extract | Out-File $outfile1
My Input:
DD/MM
27,28
14
21
1
15
7
12
2,15
25
What I'm trying to do is to add a line break for 27,28 and 2,15 so it reads each number in a separate line:
27
28
2
15
Any idea why the replace is not working here?
I have a CSV file I import, and I need to change the format of a column (backed_up_ts) to remove the original data in the column and replace it with the updated format.
The original data for each row in the column looks like this:
Tue Sep 13 07:46:26 MDT 2016
The first part of my code formats every row so that it can be compared to a date:
$csv = Import-Csv -Path "C:\Users\user\Desktop\NewReport.csv" | Select display_client_name, backed_up_ts
$csv = foreach ($budate in $csv.backed_up_ts) {
$budate = $budate.Substring(3)
$budate = $budate.Replace("MDT", "")
$budate = $budate.Replace("MST", "")
$budate = $budate.Split(" ")
$budate = $budate[1] + " " + $budate[2] + " " + $budate[5]
$budate = ($budate | Get-Date -Format d)
From here I need to take the updated format (in the $budate value) and replace the original data in the $csv.backed_up_ts array.
However, the value of $budate is only the last value of the object in the foreach loop (3/30/16).
The value of $csv.backed_up_ts remains in the array in its original format (Wednesday, August 30th, EST, 2016).
I need the original array $csv.backed_up_ts to be replaced by the coordinating values created by the $budate.
Thanks.
Updated answer based on clarification of desired transformation of data.
Code
# demonstrate changing columnn data in csv input
$input = #"
header1, header2
value11, "Tue Sep 13 07:46:26 MDT 2016"
value21, "Tue Oct 19 07:46:26 MDT 2017"
"#
$csv = ConvertFrom-Csv $input
"original"
$csv
foreach ($item in $csv)
{
# modify the header2 column in our csv input
$parts = $item.header2.Split(' ')
$newDate = $parts[1] + " " + $parts[2] + " " + $parts[5]
$item.header2 = [DateTime]::Parse($newDate) | Get-Date -Format d
}
"new"
$csv
Output
original
header1 header2
------- -------
value11 Tue Sep 13 07:46:26 MDT 2016
value21 Tue Oct 19 07:46:26 MDT 2017
new
value11 9/13/2016
value21 10/19/2017