Talk With an Expert

Month of PowerShell: Cut a Column of Text

In this article we look at cutting a column of text from a file using PowerShell.

Authored byJoshua Wright
Joshua Wright

#monthofpowershell

I work with text files all the time. My friend Ron Bowes once told me that pen tests feel like 80% converting data from one format to another. I agree, and finishing up my first week of #monthofpowershell, I still feel lost when I can't reach for [code]awk/grep/cut/sed/tr[/code]. Here's an example I needed to figure out:

PS /home/sec504> Get-Content ~/msolspray.txt
Valid user, but invalid password : Ciel.Britch@falsimentis.com
Valid user, but invalid password : Donovan.Lea@falsimentis.com
Valid user, but invalid password : Fidelity.Passo@falsimentis.com
Valid user, but invalid password : Irvine.Obbard@falsimentis.com
Valid user, but invalid password : Jeremy.Lengthorn@falsimentis.com
Valid user, but invalid password : Jillana.Walcott@falsimentis.com
Valid user, but invalid password : Kala.Edwinson@falsimentis.com
Valid user, but invalid password : Lukas.Dolman@falsimentis.com
Valid user, but invalid password : Pembroke.Trouel@falsimentis.com
Valid user, but invalid password : Rollins.Hows@falsimentis.com

I need to get the email address in a file by itself for use in subsequent password spray attacks. This is what I came up with:

PS /home/sec504> Get-Content /home/sec504/msolspray.txt | ForEach-Object { $elements = $_ -split ' '; $elements[6] }
Ciel.Britch@falsimentis.com
Donovan.Lea@falsimentis.com
Fidelity.Passo@falsimentis.com
Irvine.Obbard@falsimentis.com
Jeremy.Lengthorn@falsimentis.com
Jillana.Walcott@falsimentis.com
Kala.Edwinson@falsimentis.com
Lukas.Dolman@falsimentis.com
Pembroke.Trouel@falsimentis.com
Rollins.Hows@falsimentis.com

Let's break this command down step-by-step:

  • [code]Get-Content /home/sec504/msolspray.txt |[/code]: Retrieve the contents of the file shown above, start a pipeline
  • [code]ForEach-Object {[/code]: For each line in the file, execute the following code block
  • [code]\(elements = $_ -split ' ';[/code]: Create an array variable [code]$elements[/code] that take the current line ([code]\)_[/code]) and splits it into multiple pieces using a space ([code]' '[/code])
  • [code]$elements[6][/code]: Retrieve the 7th element in the attack (6th element offset)
  • [code]}[/code]: End the loop

After proudly showing off my work I was admonished for the unnecessary creation of the [code]$elements[/code] variable. This is a similar but more compact version that accomplishes the same task using the Grouping Operator code[/code]:

PS /home/sec504> Get-Content ~/msolspray.txt | ForEach-Object {($_ -split ' ')[6]}

Instead of declaring an array of elements by name, we create the array object by adding code[/code] around the split, accessing the 7th element of the array.

This solution gets the job done, but it feels a little ... un-PowerShell-ey. The more I work with PowerShell, the more I realize it's more than a syntax shift from Bash and other shells, it's a conceptual shift as well. Instead of treating the file as text, I could opt to treat it as a PowerShell object instead using [code]ConvertFrom-StringData[/code]:

S /home/sec504> Get-Content /home/sec504/msolspray.txt | ConvertFrom-StringData -Delimiter ':'

Name                           Value
----                           -----
Valid user, but invalid passw… Ciel.Britch@falsimentis.com
Valid user, but invalid passw… Donovan.Lea@falsimentis.com
Valid user, but invalid passw… Fidelity.Passo@falsimentis.com
Valid user, but invalid passw… Irvine.Obbard@falsimentis.com
Valid user, but invalid passw… Jeremy.Lengthorn@falsimentis.com
Valid user, but invalid passw… Jillana.Walcott@falsimentis.com
Valid user, but invalid passw… Kala.Edwinson@falsimentis.com
Valid user, but invalid passw… Lukas.Dolman@falsimentis.com
Valid user, but invalid passw… Pembroke.Trouel@falsimentis.com
Valid user, but invalid passw… Rollins.Hows@falsimentis.com
PS /home/sec504> Get-Content /home/sec504/msolspray.txt | ConvertFrom-StringData -Delimiter ':' | Select-Object -Property *
Valid user, but invalid password
--------------------------------
Ciel.Britch@falsimentis.com
Donovan.Lea@falsimentis.com
Fidelity.Passo@falsimentis.com
Irvine.Obbard@falsimentis.com
Jeremy.Lengthorn@falsimentis.com
Jillana.Walcott@falsimentis.com
Kala.Edwinson@falsimentis.com
Lukas.Dolman@falsimentis.com
Pembroke.Trouel@falsimentis.com
Rollins.Hows@falsimentis.com

By specifying the delimiter [code]:[/code] in the file, [code]ConvertFrom-StringData[/code] converts each line into a PowerShell object, allowing me to retrieve the email addresses as an object property, instead of parsing the string output.

This also does feel quite-right, but it's time to get back to the pen test. In a future article I'll dig more into the [code]ConvertFrom[/code] family of commands, and how we can use them to take structured and unstructured data, and convert it to standard PowerShell objects.

-Joshua Wright


Joshua Wright is the author of SANS SEC504: Hacker Tools, Techniques, and Incident Handling, a faculty fellow for the SANS Institute, and a senior technical director at Counter Hack.