Content

PowerShell Basics-Filtering and Iterating over Objects

Now that we know that commands in PowerShell produce objects and that they have properties we can now start comparing, filtering and manipulating the objects.

Operators

For the manipulation of objects we will cover first the Operators in PowerShell since they are used against Objects and the Properties of objects. You will notice that the operators for comparison operators in PowerShell will differ from those in Ruby, Python, Perl and other scripting languages and mimic more those found in Unix type shells so a Bash programmer will feel at ease with the operators in PowerShell. When comparisons are done PowerShell has the special variables $True and $False to represent Boolean values.

image

One thing to keep in mind when working with PowerShell is that it is case insensitive so when we are doing comparisons and we want them to be case sensitive we have to explicitly specify to be case sensitive.

PS > "hello" -eq "HELLO"
True

To make a comparison be case sensitive one only need to add a c to the comparison.

PS > "hello" -ceq "HELLO"
False

PowerShell will try to convert the types of the element for evaluation by analyzing them. It ill use the value on the left as the type to convert the type on the right.

PS > 1 -eq "1"
True

There are also operators for comparing collections and type:

image

One common mistake by many starting with PowerShell is that many times -contains and -in operators are used by mistake to search in strings. Their use is for Arrays or Hash lists.

PS > "a","b","c" -contains "b"
True
PS > "b" -in "a","b","c"
True

PowerShell also allow also to compare by type. The operators are: Type operators are mostly used to make sure the proper type is used in scripts

C:PS> (get-date) -is [datetime]
True
C:PS> (get-date) -isnot [datetime]
False
C:PS> "9/28/12" -as [datetime]
Friday, September 28, 2012 12:00:00 AM 

We can join several comparisons using Boolean Operators and each comparison operator is considered a subexpression.

image

Subexpressions can be parenthetical or cmdlets that return a Boolean. An example would be :

PS C:> ((1 -eq 1) -or (15 -gt 20)) -and ("running" -like "*run*")
True

Selecting Objects

The Select-Object cmdlet allows for:

  • Selecting specific objects or a Range of objects from an ordered collection of objects that contains specific properties.
  • Selecting a given number from the beginning or end of a ordered list of objects.
  • Select specific properties from objects.
  • Creation of new object with properties Renaming object properties .

The Select-Object cmdlets allows us to select from a collection of objects the ones we want when we specify the index position of the item. Just like all programing languages we start our count with 0.

PS > Get-Process | Sort-Object name -Descending | Select-Object -Index 0,1,2,3,4 

We can also use the range notation, this will return an array of number for the range and we can pass those to the index parameter.

PS > Get-Process | Sort-Object name -Descending | Select-Object -Index (0..4)

Select the first number of objects, the last number of objects or even skip a certain number.

PS > Get-Process | Sort-Object name -Descending | Select-Object -first 5 

The select-object cmdlets also allows us to create and rename an objects property, this is very useful when the property name is not to descriptive and when we are passing from one comdlet to another where the next cmdlet accepts and processes objects by Property Name. The way it works is that we create a hash with 2 values in it, one is Name which is the name we ant for the property and the other is expressions which is a script block whose returning value will be set as the value of the property we named.

PS > Get-Process | Select-Object -Property name,@{name = 'PID'; expression = {$_.id}} 

One thing that we have to be very careful with when using Select-Object is that when we select property names using it actually generates a new object of the same type with only those properties that we selected and strips out the rest. Depending on the chaining of cmdlets using the pipeline this could cause us to loose a property we may need further along the pipeline chain so do keep it in mind and be careful.

Iterating over Objects

Iteration is the method by which several objects in a collection are processed one by one and actions are taken against them. In PowerShell, there are 2 methods for iterating thru objects and are often confused:

  • ForEach-Object cmdlet and its aliases foreach and %.
  • foreach( in ){} statement.

As you can see the main reason for the confusion is that Foreach-Object has an alias of foreach which can be confused with the statement. Each method will take a collection and process the objects in a Scriptblock but each behaves differently, however and its use will vary case by case.

Lets start with Foreach-Object. The ForEach-Object cmdlet takes a stream of objects from the pipeline and processes each and it uses less memory do to garbage control, as objects gets processed and they are passed thru the pipeline they get removed from memory. The cmdlet takes 4 main parameters:

  • Begin <Script block> executed before processing all objects
  • Process <Script block> executed per each object being processed
  • End <Script block > to be executed after all objects have been processing all objects.
  • InputObject <PSObject> to take actions against. Typically this is taken thru the pipeline.

The ScriptBlocks parameters are also positional

PS C:> 1..5 | ForEach-Object { $Sum = 0 } { $Sum += $_ } { $Sum }
15 

To skip to the next object to be process in ForEach-Object the keyword Continue is used. For exiting the loop inside of a ForEach-Object the break keyword is used.

C:PS> $Numbers = 4..7
C:PS> 1..10 | foreach-object { if ($Numbers -contains $_) { continue }; $_ }
1
2
3 

Now lets take a look at the at the Foreach statement. The foreach( in ){} statement places on each iteration an element of a collection in to memory first and then processes each. (Not good for extremely large collections on memory constrained systems). Since the collection being worked on is loaded in to memory it tends to be faster than the ForEach-Object cmdlet.

To skip to the next object to be process in foreach statement the keyword continue is used. For exiting the loop inside of a foreach statement the break keyword is used.

  • The foreach statement has a special variable called $foreach with 2 special methods that can be used: $foreach.MoveNext() to skip to the next element in the collection and continue to process the next element in the collection. Returns a Boolean true value that should be handled.
  • $foreach.Current to represent the current element being processed

The foreach statement can even be used in a interactive shell session:

PS >foreach ($i in (1..10)){
>>    if ($i -gt 5){
>>        continue
>>    }
>>    $i
>> }
>>
1
2
3
4
5 

As always I hope you have found this blogpost informative and useful. Thanks.

Carlos Perez

Carlos is currently the Principal Consultant, Team Lead for Research at TrustedSec and well-known for his research on both Metasploit and Windows Powershell. His blog www.darkoperator.com carries the tag line: “Shell Is Only The Beginning”.

Get daily email updates

SC Media's daily must-read of the most current and pressing daily news

By clicking the Subscribe button below, you agree to SC Media Terms and Conditions and Privacy Policy.