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'