This is the second part of the blog post series of learning PowerShell. Before we start on this post there is are two concepts that I want to define. The first is the term collections. As previously discussed in the last post PowerShell is object orientated but we not only deal with one object at a time, we can deal with a lot of objects at a time.
So what is an example of collection? Lets say we run this command:
get-childitem "c:\temp" -File
and we get back:
FullName Length
-------- ------
C:\temp\ansiblehosts.txt 460
C:\temp\cert.cer 1042
C:\temp\current_servers.csv 309
C:\temp\current_servers.txt 309
C:\temp\GPOResult.xml 213426
C:\temp\html.html 89696
C:\temp\IMG_4203.JPG 3210248
C:\temp\install_pswindows_psmodule.tar 5120
C:\temp\jenkins.crt 2226
C:\temp\jenkins.key 3324
This list of files is called a ‘collection’.
The second is parameters. I covered briefly in the last post. But I am going to discuss it further. in additional to a cmdlet, cmdlets come with parameters. You can consider them like the switches in other command interpreters like DOS or bash in Linux. The description on how they are used in Get-Help.
So what do I mean by workhorse commands? These are commands that that wil be used over and over again in your PowerShell career. 70% of the time I have found when scripting in PowerShell, I have found myself navigating through objects. Filtering through collections(a bunch of objects), so its important to understand the core usage of how they work.
The key commands that we are going to be talking about are:
Select-Object
Where-Object
Sort-Object
Group-Object
Measure-Object
There is a lot going on with each of these commands so I am just going to cover the basics in this post on how they work. For further information on certain examples you can use Get-Help -full .
Select-Object
Select-Object is a command that allows you to select properties from an object. So going back to our previous command I am going to pipe the results to select-object and see what comes back:
get-childitem "c:\temp" -File | select-object fullname , length -first 5
In my example PowerShell returns back to me the following:
FullName Length
-------- ------
C:\temp\ansiblehosts.txt 460
C:\temp\cert.cer 1042
C:\temp\current_servers.csv 309
C:\temp\current_servers.txt 309
C:\temp\GPOResult.xml 213426
So what happened? We produced a list of files under c:\temp , and then passed the collection to Select-Object. Because we gave two properties, Select-Object then displayed those properties only displaying the first 5.
So the question might be: how do I know what properties to return? I cannot see the property that I am looking for….
This is where the Get-Member cmdlet is so invaluable. In the previous cmdlet we can see the properties of the cmdlet by typing:
Get-Childitem c:\temp | Get-Member -MemberType property
TypeName: System.IO.FileInfo
Name MemberType Definition
---- ---------- ----------
Attributes Property System.IO.FileAttributes Attributes {get;set;}
CreationTime Property datetime CreationTime {get;set;}
CreationTimeUtc Property datetime CreationTimeUtc {get;set;}
Directory Property System.IO.DirectoryInfo Directory {get;}
DirectoryName Property string DirectoryName {get;}
Exists Property bool Exists {get;}
Extension Property string Extension {get;}
FullName Property string FullName {get;}
IsReadOnly Property bool IsReadOnly {get;set;}
LastAccessTime Property datetime LastAccessTime {get;set;}
LastAccessTimeUtc Property datetime LastAccessTimeUtc {get;set;}
LastWriteTime Property datetime LastWriteTime {get;set;}
LastWriteTimeUtc Property datetime LastWriteTimeUtc {get;set;}
Length Property long Length {get;}
Name Property string Name {get;}
This is what is returned. All of these properties is what you can pass to Select-Object for the cmdlet Get-Childitem. You can also use the unique parameter to limit down duplicate values from a property.
Another example that will work:
get-childitem "c:\temp" -File | select-object fullname , length , LastWritetime, LastAccessTime, -Last 5
Where-Object
The cmdlet Where-Object is used for ‘filtering’. Ever asked those questions where you might say I only want to see those files that have been written to in the last 10 days? Or I only want to see items with a certain criteria.
In order to make this query PowerShell uses what they call by ‘comparison operators’ . In pseudo code it will look like this:
Find all the files in the temp directory that is older than 3 days. In PowerShell it will look like this:
Get-ChildItem $env:temp -Recurse | Where-Object {$_.lastaccesstime -lt ((Get-date).adddays(-3)}
The full list can be found by going to:
Get-Help about_Comparison_Operators
Here is the list:
Comparison Operator | Description |
-eq | This means equal. get-childitem $env:temp | where-object {$_extension -eq .xml} |
This finds all the files in the $env:temp directory that has the extension xml. One thing to note this absolute. You cannot use wild cards here. Use -like if you want to use wildcards | ||
-ne | This is the opposite of -eq. get-childitem $env:temp | where-object {$_.extension -ne .xml} |
This finds all the files in the $env:temp directory that does not have extension xml. One thing to note this absolute. If you want to use wildcards you have to use -notlike | ||
-gt | This means greater than . Get-ChildItem $env:temp -Recurse | Where-Object {$_.lastaccesstime -gt ((Get-date).adddays(-3)} |
These gets the files that have been accessed three days ago. (Get-Date) is an object and we use the method of adddays to add -3 days. | ||
-ge | Greater than or Equals to. This works in much the same way as -gt but includes the value compared against. | |
-lt | Less than .Its used the same as gt but in reverse. | |
-le | Less than or equals to .Its used the same as gt but in reverse. | |
-Like | Like is similar to -eq but you can use wild cards with like . | |
get-childitem $env:temp | where-object {$_.fullname -like “listservers” } | |
-NotLike | Notlike is the opposite of like but you can use it in the same way as like. It will exclude the terms that you put in. | |
-Match | This uses regex to match get-childitem -recurse | where-object {$_.fullname -match “tables”} |
This searches the file listing with get-childitem and finds files with the regex ‘tables’ | ||
-NotMatch | This is the opposite of match and removes the objects that matches the regex. | |
-Contains | This expression relates to whether or not an item exists in a collection of items. The idea is that you provide a collection of objects. It detects whether the item exists in the collection | |
((get-childitem -recurse).name) -contains ‘tables.scss’ This shows properties of name in the current directory and detects whether it contains the file tables.scss. Shows true or false | ||
-NotContains | This is the opposite of -contains | |
-In | This is the same as contains but its the opposite way of writing. ‘tables.scss’ -in ((get-childitem -recurse).name) | |
-NotIn | Opposite of -In | |
-Replace | Replaces a text. ‘tables.scss’ -replace ‘tables.scss’, ‘test’ | |
This will replace the text tables.scss with the word test. |
You can join expressions together with -and or -or.
This is one example of using -and.
Get-ChildItem $env:temp -Recurse | Where-Object {$_.lastaccesstime -gt (Get-date).adddays(-1) -and $_.extension -like "*.exe*"}
Sort-Group
This cmdlet is used to sort objects. The basic of using this command is like:
Get-ChildItem $env:temp -Recurse | Sort-Object -property name
Get-ChildItem $env:temp -Recurse | Sort-Object -property name -Descending
This will sort the collection by the property ‘name’ and the second line sorts it by descending order.
Group-Object
This cmdlet will group what you pass it a collection. You name a property that you want to group Example is below:
Get-ChildItem $env:temp -Recurse | Group-Object extension
Measure-Object
This cmdlet measures the collection that you are passing it over the pipeline.
Get-ChildItem $env:temp -Recurse | Measure-Object
This is the result:
Count : 317
Average :
Sum :
Maximum :
Minimum :
Property :
Piecing it all together
So now we have explained how to use these cmdlets at a basic level the question is how can we use these cmdlets together? Before we explore this there are some things that we got to cover. That is filter left and format right.
There is another command that there starts Format*. We will discuss this cmdlet later but for now remember “Filter Left , Format Right” Let’s see an example of how to piece it together:
Get-ChildItem $env:temp -Recurse | Where-Object {$_.lastaccesstime -lt (Get-date).adddays(-3)}| Sort-Object -property fullname | Select-Object -property fullname , lastaccessdate, extension -first 5
So here is the breakdown of what is happening. We produced a set of objects through Get-Childitem and then we pass that across the pipeline to Where-Object. The object is then passed to within the script block where it is evaluated to see whether it matches the condition in the script block. The object that do not match the comparison will get dropped and the remaining object then get passed across the pipeline to sort-object with the property fullname. The objects then pass down the cmdlet Select-Object where the only properties kept is fullname, lastaccessdate, extension.
FullName LastAccessTime Extension
-------- -------------- ---------
C:\Users\weiyentan\AppData\Local\Temp\{0A07A017-27B9-4092-8E64-1A43528BAD74} - OProcSessId.dat 6/01/2020 7:33:17 PM .dat
C:\Users\weiyentan\AppData\Local\Temp\{3F44DF31-C470-4A78-9282-F5CBD809B72B} - OProcSessId.dat 22/12/2019 11:07:01 PM .dat
C:\Users\weiyentan\AppData\Local\Temp\{72FDE0E5-5FB6-4C75-A20D-9BD3E32F0996}.png 6/01/2020 7:16:19 PM .png
C:\Users\weiyentan\AppData\Local\Temp\{7BB95D4C-695C-442A-A9E6-2678005C61D6} - OProcSessId.dat 23/12/2019 2:22:26 PM .dat
C:\Users\weiyentan\AppData\Local\Temp\{823C1E9F-2BC6-446D-89B4-1FD179F62200} - OProcSessId.dat 18/12/2019 7:39:46 PM .dat
So why is it important to filter left? Lets see what happens.
Get-ChildItem $env:temp -Recurse | Select -property fullname , extension -first 5 | Where-Object {$_.lastaccesstime -lt (Get-date).adddays(-3)}
We are creating a list of objects and then we select only fullname , lastaccessdate, extension and then pass that to where-object. And thats where it all balks because it can’t find the property lastaccesstime
These cmdlets are what you are going to use most of the time. Once you understand how to dissect objects and navigate and filter it will make your journey learning PowerShell a lot easier. Happy PowerShelling!