Retrieving two lines from text files in folder and appending to a file

I need to pull out two lines of text from multiple text files and put them into one CSV file.

=============================

Sample data:

File1.txt

User=asfd
UserID=12
Computer=12343
Name=Smith, Will

File2.txt

User=qwerty
UserID = 14
Computer=4567
Name=Smith, John

File3.txt

User=asfd
UserID=12
Computer=123434
Name=Smith, William

=============================

I want to pull out the two lines that are UserID & Name and put those into a CSV that is structured like this:

UserID,Name
12;Smith, William
12;Smith, Will
14; Smith, John

I am currently using:

Get-Content $TextFilesInDirectory | Select-String -Pattern "^Name=" | Out-File C:\TMP\Names.csv

but I can’t put this into the same file as

Get-Content $TextFilesInDirectory | Select-String -Pattern "^UserID=" | Out-File C:\TMP\Names.csv

Any suggestions?

It’s certainly not a one-liner, but it uses Regex and parses the files into their own PSObjects (which can then exported to CSV).

$allTxtFiles = Get-ChildItem -Path $TextFilesInDirectory

$allInfo = foreach ($file in $allTxtFiles) {

    $raw = Get-Content -Path $file.FullName -Raw

    $matchGrps = [regex]::Matches($raw, '^(.+)?\=(.+)$', "Multiline")
    
    $props = @{}
    foreach ($grp in $matchGrps) {

        $name = $grp.Groups[1].Value.Trim()
        $value = $grp.Groups[2].Value.Trim()
        $props.Add($name, $value)
    }
    New-Object PSObject -Property $props
}

$allInfo | Export-Csv "C:\TMP\Names.csv" -NoTypeInformation

# The output looks like:

# User   UserID Computer Name
# ----   ------ -------- ----
# asfd   12     12343    Smith, Will   
# qwerty 14     4567     Smith, John   
# asfd   12     123434   Smith, William

Not counting string splitting/manipulation, I see 3 possible solutions: using Select-String with regex like you are, ConvertFrom-String, and ConvertFrom-StringData.

Select-String

get-content $textfiles -raw | Select-String "(?s)UserID[?=\ ]*([\d]*).*Name[?=\ ](.*)" | foreach {
    [PSCustomObject]@{
        UserID = $_.matches.groups[1]
        Name   = $_.matches.groups[2]
    }
} -OutVariable results | Export-CSV C:\TMP\Names.csv -NoType

Output

UserID Name          
------ ----          
12     Smith, Will   
14     Smith, John   
12     Smith, William

ConvertFrom-String

Now this one assumes you have more than one entry per file, otherwise why are you automating it? :slight_smile: Need to give enough training data without going overboard. For this I have combined the 3 users into one file. Closer to real sample data may be better to train with.

@'
User=asfd
UserID=12
Computer=12343
Name=Smith, Will
User=qwerty
UserID = 14
Computer=4567
Name=Smith, John
User=asfd
UserID=12
Computer=123434
Name=Smith, William
'@ | Out-File c:\TMP\alltext.txt

$template = @'
User=asfd
UserID={User*:{UserID:12}
{!UserID:Computer=12343}
Name={[string]Name: Smith, Will}}

User = qwerty
UserID ={User*:{UserID:14}
{!UserID:Computer =4567}
Name ={[string]Name:Smith, John}}
'@
Get-Content c:\temp\alltext.txt -Raw |
    ConvertFrom-String -TemplateContent $template |
        select -ExpandProperty user | Export-Csv C:\TMP\Names.csv -NoTypeInformation

The contents of the csv

import-csv C:\TMP\Names.csv

UserID Name          
------ ----          
12     Smith, Will   
14     Smith, John   
12     Smith, William

I haven’t quite figured ConvertFrom-StringData out all the way. I say it seems like a good fit because the data is already in the “name=value” format. Maybe someone else can add an example using that.

ConvertFrom-StringData will convert a string into a hash table, but the key has to be unique. In the “alltext.txt” example that Doug gives, ConvertFrom-StringData will fail as the keys (ie User in User=qwery) has already been defined (User=asfd).

If they are all seperate files, something like this should work;

$file1 = @'
User=asfd
UserID=12
Computer=12343
Name=Smith, Will
'@

$File2 = @'
User=qwerty
UserID = 14
Computer=4567
Name=Smith, John
'@

$File3 = @'
User=asfd
UserID=12
Computer=123434
Name=Smith, William
'@

$files = $file1, $file2, $File3

$output = @()


foreach ($file in $files)
{
$info = $null
$info = ConvertFrom-StringData $file -Delimiter '='
$i = [pscustomobject]@{
UserID = $info.UserID
Name = $info.name
}
$output += $i
$i = $null
}

$output

Thank you all so much, you got me going in the right direction!

Good deal. Just to be thorough for myself and future readers, here is another way using plain ol’ string manipulation.

$TextFilesInDirectory = 'C:\some\path\file*.txt'

Get-ChildItem $TextFilesInDirectory | foreach{
    $userid,$name = foreach($line in Get-Content $_){
        'UserID','Name' | foreach{
            if($line -match $_){$line.split('=').trim()[1]}  
        }
    }
    [PSCustomObject]@{
        UserID = $userid
        Name   = $name
    }
} | Export-Csv C:\TMP\Names.csv -NoTypeInformation

Doug, this is the method I ended up using!

https://powershell.org/forums/topic/retrieving-two-lines-from-text-files-in-folder-and-appending-to-a-file/#post-249716

It just linked to this thread, so not sure which one you used. I also wanted to share my ConvertFrom-StringData solution.

$TextFilesInDirectory | foreach {
    $ht = @{}
    Get-Content $_ | ConvertFrom-StringData | foreach {$ht += $_}
    [PSCustomObject]$ht
}

Output

User   UserID Computer Name          
----   ------ -------- ----          
asfd   12     12343    Smith, Will   
qwerty 14     4567     Smith, John   
asfd   12     123434   Smith, William

To limit to just the 2 desired properties

$TextFilesInDirectory | foreach {
    $ht = @{}
    Get-Content $_ | ConvertFrom-StringData | foreach {$ht += $_}
    [PSCustomObject]$ht
} | select UserID,Name

As desired

UserID Name          
------ ----          
12     Smith, Will   
14     Smith, John   
12     Smith, William

That worked fine because there is only one set per file. However it’s likely to have many per file. If the files hav each set separated by a blank line, you can use this approach.

(get-content $combinedfiles -raw) -split '(?m)^[^\S]' | foreach {
    $ht = @{}
    $_ | convertfrom-StringData | foreach{$ht += $_}
    [PSCustomObject]$ht
}

This will split each group at the blank line and then process each line of each group the same way as before.

Oops, https://powershell.org/forums/topic/retrieving-two-lines-from-text-files-in-folder-and-appending-to-a-file/#post-249716 Post#: 249716