Training
Get a free hour of SANS training

Experience SANS training through course previews.

Learn More
Learning Paths
Can't find what you are looking for?

Let us help.

Contact us
Resources
Join the SANS Community

Become a member for instant access to our free resources.

Sign Up
For Organizations
Interested in developing a training plan to fit your organization’s needs?

We're here to help.

Contact Us
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.

Month of PowerShell: Cut a Column of Text | SANS Institute