0

I have a text file with multiple users (in the exact format):

username:t-Hancock

phoneNumber: 555555555

username:a-smith

PhoneNumber: 987654321

username:r-Byer

phonenumber: 123456789

I am trying to get all these users into an object with two properties (name and phone number). I tried Get-Content, tried some regex from other posts, but I couldn't modify them because I didn't understand it.

How could this be done?

3
  • Can you show what you have tried? You will usually get a better response if you do Commented May 2, 2015 at 8:24
  • Does the text in the file really have a blank line between each line of text? Commented May 2, 2015 at 9:05
  • Why three different spellings, "phoneNumber", "PhoneNumber", and "phonenumber"? Commented Mar 1, 2019 at 13:10

3 Answers 3

3

It's not that clear entirely what you want here - what kind of object and for what purpose?

I'll go with an example of what you could do...

Say you want to convert that text file into a CSV file for easy import into Excel, start with reading the file content:

$input = Get-Content C:\TextFile.txt

Now, create an array into which you will store each object you create:

$array = @()

Now, we will go into a loop, parsing the file contents. If the line starts with "username", split the line using colon as delimiter, grab the second item (0-relative so the second item is number one) into a variable.

If the line starts with "PhoneNumber" then set the $writeobj variable to true (reset to false at the start of each iteration of the loop) and store the "PhoneNumber" value in $PhoneNumber using split again.

Then check if $writeobj is true and, if so, create a new object, add a NoteProperty with name of Username and username value stored from a previous line in the file.

Then add a NoteProperty with name PhoneNumber and value of $PhoneNumber. Then, add the object to the array.

This repeats all the way through the file contents:

$input | foreach-object {
    $writeobj = $false
    $obj = New-Object System.Object
    If ($_ -match 'username*') {
        $Username = ($_ -split ':')[1]
    }
    If ($_ -match 'PhoneNumber*') {
        $PhoneNumber = ($_ -split ':')[1]
        $writeobj = $true
    }
    If ($writeobj){
        $obj | Add-Member -type NoteProperty -name Username -value $Username
        $obj | Add-Member -type NoteProperty -name PhoneNumber -value $PhoneNumber
        $array += $obj
    }
}

Once we're out of the loop, export the array to a CSV file:

$array | Export-Csv -path C:\test.csv -NoTypeInformation

So, the full script is:

$input = Get-Content C:\TextFile.txt
$array = @()
$input | foreach-object {
    $writeobj = $false
    $obj = New-Object System.Object
    If ($_ -match 'username*') {
        $Username = ($_ -split ':')[1]
    }
    If ($_ -match 'PhoneNumber*') {
        $PhoneNumber = ($_ -split ':')[1]
        $writeobj = $true
    }
    If ($writeobj){
        $obj | Add-Member -type NoteProperty -name Username -value $Username
        $obj | Add-Member -type NoteProperty -name PhoneNumber -value $PhoneNumber
        $array += $obj
    }
}
$array | Export-Csv -path C:\test.csv -NoTypeInformation

See the screenshot below of a CSV file opened in Excel.

Example CSV file opened in Excel

Sign up to request clarification or add additional context in comments.

4 Comments

Amended my solution to use -match instead of .Startswith as it wasn't giving good results, showing only the middle user, a-smith, in the final CSV file. Also amended loop logic to be more robust, and added screenshot of the CSV that the script creates, in excel.
The sample input file has 3 different spellings, "phoneNumber", "PhoneNumber", and "phonenumber". Perhaps something should be said in this answer about case sensitivity (e.g. "the -match operator is not case-sensitive by default" or something (I haven't checked if that is actually the case (no pun intended) or not))?
@PeterMortensen the solution provided is case-insensitive, as the screen grab of the produced CSV file demonstrates - using the same input data the output has three records in the csv just as there are three records in the input day. Powershell is largely case insensitive by default and the match operator is no different. If you wanted it to be case sensitive use the -cmatch operator instead which is explicitly case sensitive.
This just saved my life. I've got 9,000+ users and makes a horribly flat list. Thank you!!!
0

I suggest you to change your format to CSV instead, and then it's very trivial. Just use Import-Csv.

Right now you could do something a long of the lines, it assumes valid text file, no empty lines:

$content = Get-Content "C:\Users\You\Documents\test.txt"
$readUsername = $true
$data = @()
foreach ($line in $content)
{
    if($readUsername -eq $true) {
      $username = .. # Match the line against regex.
      $readUsername = $false
    } else {
       $phone = .. # Match the line against regex
       $readUsername = $true

       # We have grabbed username & phone
       $props = @{Name: $username, Phone: $phone}
       $obj = New-Object PSObject –Property $props
       $data += $obj
    }
}

# You now have access to $data.

Comments

0

I would use regexes to get at the data (example below), and you may need to tweak the regexs to extract the names and numbers, because I only had your small sample to go on and I have made some assumptions like no spaces in the names and numbers.

((Get-Content file.txt -Raw) -split '\n(?=username)') | % {
    $x = $_ -split '\r'
    New-Object PSOBJECT -Property @{
        name  = [regex]::Match($x[0],'(?<=username:\s*)\b.*\b')
        phone = [regex]::Match($x[1],'(?<=[Pp]hone[Nn]umber:\s*)\b.*\b')
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.