We are still actively working on the spam issue, the wiki may be restored to an earlier date and account creation may be disabled.

Powershell

From InstallGentoo Wiki
Jump to: navigation, search

Windows Powershell is a shell / scripting environment created by Microsoft. You can read more about the technical stuff. This page serves as not a complete description of Powershell or its history, but a guide on how to use it. Some programming knowledge is expected but not absolutely required. Experience with bash is also probably helpful, but you could learn something even if you have zero experience with any kind of shell or scripting environment.

Rationale

I think Powershell is pretty neat. I used Linux as my main OS for about 5 years and had to switch to Windows very recently for a myriad of reasons. Ironically I might have to switch back soon (taking a *NIX Systems Programming class), but in the meantime I wanted a scripting language for Windows that was better for the everyday grind than Python, so I did some research and found Powershell. Its no bash, but its close, and I think if it was embraced by the world and the Internet (re: people give M$ a reason to care about it) then it could be really great. The fact that Microsoft is actively trying to make Windows a more dev-friendly environment shows that exciting things are happening (See: SSH on Windows), and I believe those changes will start begin with the upcoming changes to Powershell in Windows 10.

- Anon, June 9th 2015

Getting Started

Here is a chart that I made. File:PsQuickReference-20150609.pdf (I made it as a .pdf because I can't be assed to learn how to use WikiMedia properly, so if you don't like that please contribute yourself.) It was designed to get someone familiar with the *NIX shell up and scripting as fast as possible, and includes all the common commands I remember using often on *NIX.

Let's do a quick analysis of this chart and come up with some pros and cons.

Pros of Powershell:

  • Syntax is sometimes much clearer than bash. Powershell's syntax is also much more consistent. This makes it much easier to compose and read scripts.
  • Syntax is generally not case sensitive. Some people might put this as a con but I like it and I think many others do too.
  • Familiar conventions to get *NIX people started, such as $ for variables, cp, mv, mkdir, etc.
  • Familiar object-oriented conventions are baked in. If you come from a Java, C#, or even Ruby background, lots of things should feel familiar.
  • Decently fast, both performance-wise and to learn.
  • .NET environment, meaning its extensible with your own .NET objects. * Lots of juicy default aliases for juicy shortcuts. You can tell whoever wrote this shit actually uses a shell.
  • Access to lots of Windows APIs/features such as the registry and Internet Explorer.
  • Powershell Community Extensions and/or PsGet.
  • Its not cmd.exe ! ! !

Cons of Powershell:

  • Windows only, whereas bash or sh is on basically every OS (including Windows with Cygwin).
  • Cannot run scripts by default, and Powershell only comes by default with Win7 and up. Makes scripts unportable because they are not necessarily guarunteed to run on another machine.
  • Sometimes the commands are quite verbose. It can be especially annoying to type out very verbose arguments, such as '-Recurse' as opposed to '-r'.
  • Fairly slow autocomplete (hopefully will be fixed in Windows 10).
  • No reverse i-search by default.
  • Capitals everywhere. Why? I know it usually doesn't matter but its still kind of ugly.
  • Binary logs (Get-History is an example, I think).

Initial Configuration

First thing you're gonna wanna do is fix Microsoft's idiocy and make scripts executable. To do that, run this command:

   Set-ExecutionPolicy -CurrentUser RemoteSigned

You might need to do it in an elevated prompt. To do that, open the Start Menu, type 'Windows Powershell', right-click the link, and select 'Run as Administrator'. Then enter the command.

Next, you'll probably want a config file to store custom aliases, functions, and the like. To do this, run this little snippet:

   if ( -Not (Test-Path $profile)) {
       New-Item -Type File $profile
   }
   Notepad $profile

This will be where you store your customized Powershell configuration.

Some Helpful Default Aliases

Here are some useful aliases that are baked into Powershell. You'll probably find yourself using them often, and they may seem familiar, so take a good, long look.

   CommandType     Name
   -----------     ----
   Alias           % -> ForEach-Object
   Alias           % -> ForEach-Object
   Alias           ? -> Where-Object
   Alias           h -> Get-History
   Alias           r -> Invoke-History
   Alias           ac -> Add-Content
   Alias           cd -> Set-Location
   Alias           compare -> Compare-Object
   Alias           cp -> Copy-Item
   Alias           curl -> Invoke-WebRequest
   Alias           diff -> Compare-Object
   Alias           foreach -> ForEach-Object
   Alias           ft -> Format-Table
   Alias           fw -> Format-Wide
   Alias           gc -> Get-Content
   Alias           kill -> Stop-Process
   Alias           ls -> Get-ChildItem
   Alias           man -> help
   Alias           measure -> Measure-Object
   Alias           nal -> New-Alias
   Alias           nv -> New-Variable
   Alias           ps -> Get-Process
   Alias           pwd -> Get-Location
   Alias           r -> Invoke-History
   Alias           ren -> Rename-Item
   Alias           rm -> Remove-Item
   Alias           rmdir -> Remove-Item
   Alias           rv -> Remove-Variable
   Alias           sc -> Set-Content
   Alias           select -> Select-Object
   Alias           sort -> Sort-Object
   Alias           start -> Start-Process
   Alias           sv -> Set-Variable
   Alias           tee -> Tee-Object
   Alias           type -> Get-Content
   Alias           wget -> Invoke-WebRequest
   Alias           where -> Where-Object

To view aliases, use Get-Alias. To edit them, use New-Alias and Set-Alias.

Getting Help

As you can see above, man is an alias for a command called Get-Help. It does exactly what you think it does.

   PS C:\> get-help get-help
   NAME
       Get-Help
   
   SYNTAX
       Get-Help [[-Name] <string>] [-Path <string>] [-Category <string[]> {Alias | Cmdlet | Provider | General | FAQ
       | Glossary | HelpFile | ScriptCommand | Function | Filter | ExternalScript | All | DefaultHelp | Workflow}]
       [-Component <string[]>] [-Functionality <string[]>] [-Role <string[]>] [-Full]  [<CommonParameters>]
   
       Get-Help [[-Name] <string>] -Detailed [-Path <string>] [-Category <string[]> {Alias | Cmdlet | Provider |
       General | FAQ | Glossary | HelpFile | ScriptCommand | Function | Filter | ExternalScript | All | DefaultHelp |
       Workflow}] [-Component <string[]>] [-Functionality <string[]>] [-Role <string[]>]  [<CommonParameters>]
   
       Get-Help [[-Name] <string>] -Examples [-Path <string>] [-Category <string[]> {Alias | Cmdlet | Provider |
       General | FAQ | Glossary | HelpFile | ScriptCommand | Function | Filter | ExternalScript | All | DefaultHelp |
       Workflow}] [-Component <string[]>] [-Functionality <string[]>] [-Role <string[]>]  [<CommonParameters>]
   
       Get-Help [[-Name] <string>] -Parameter <string> [-Path <string>] [-Category <string[]> {Alias | Cmdlet |
       Provider | General | FAQ | Glossary | HelpFile | ScriptCommand | Function | Filter | ExternalScript | All |
       DefaultHelp | Workflow}] [-Component <string[]>] [-Functionality <string[]>] [-Role <string[]>]
       [<CommonParameters>]
   
       Get-Help [[-Name] <string>] -Online [-Path <string>] [-Category <string[]> {Alias | Cmdlet | Provider |
       General | FAQ | Glossary | HelpFile | ScriptCommand | Function | Filter | ExternalScript | All | DefaultHelp |
       Workflow}] [-Component <string[]>] [-Functionality <string[]>] [-Role <string[]>]  [<CommonParameters>]
   
       Get-Help [[-Name] <string>] -ShowWindow [-Path <string>] [-Category <string[]> {Alias | Cmdlet | Provider |
       General | FAQ | Glossary | HelpFile | ScriptCommand | Function | Filter | ExternalScript | All | DefaultHelp |
       Workflow}] [-Component <string[]>] [-Functionality <string[]>] [-Role <string[]>]  [<CommonParameters>]
   
   ALIASES
       None
   
   REMARKS
       Get-Help cannot find the Help files for this cmdlet on this computer. It is displaying only partial help.
           -- To download and install Help files for the module that includes this cmdlet, use Update-Help.
           -- To view the Help topic for this cmdlet online, type: "Get-Help Get-Help -Online" or
              go to http://go.microsoft.com/fwlink/?LinkID=113316.

And we get a nice little description of Get-Help and its parameters. It resembles a man page, quite intentionally. Get-Help works with any command and any alias, and is aliased to man. Some useful parameters to Get-Help are -Online and -ShowWindow for the GUI babbies and -Example for hands-on learners.

If you notice in the 'Remarks' section, Powershell has the unhelpful feature of not actually coming with complete documentation. To fix this, use the cmdlet Update-Help, either standalone or with a cmdlet passed as a parameter, to download the online help files to your local machine.

Another great tool for getting help is Get-Member. Unsure of how to use an object? Piping it to Get-Member will display all the object's data members and methods so that you can find and use the one you want.

   PS C:\> "abcd" | get-member
      TypeName: System.String
   
   Name             MemberType            Definition
   ----             ----------            ----------
   Clone            Method                System.Object Clone(), System.Object ICloneable.Clone()
   CompareTo        Method                int CompareTo(System.Object value), int CompareTo(string strB), int IComp... Contains         Method                bool Contains(string value)
   CopyTo           Method                void CopyTo(int sourceIndex, char[] destination, int destinationIndex, in... EndsWith         Method                bool EndsWith(string value), bool EndsWith(string value, System.StringCom... Equals           Method                bool Equals(System.Object obj), bool Equals(string value), bool Equals(st... GetEnumerator    Method                System.CharEnumerator GetEnumerator(), System.Collections.Generic.IEnumer... GetHashCode      Method                int GetHashCode()
   GetType          Method                type GetType()
   GetTypeCode      Method                System.TypeCode GetTypeCode(), System.TypeCode IConvertible.GetTypeCode()
   IndexOf          Method                int IndexOf(char value), int IndexOf(char value, int startIndex), int Ind... IndexOfAny       Method                int IndexOfAny(char[] anyOf), int IndexOfAny(char[] anyOf, int startIndex... Insert           Method                string Insert(int startIndex, string value)
   IsNormalized     Method                bool IsNormalized(), bool IsNormalized(System.Text.NormalizationForm norm... LastIndexOf      Method                int LastIndexOf(char value), int LastIndexOf(char value, int startIndex),... LastIndexOfAny   Method                int LastIndexOfAny(char[] anyOf), int LastIndexOfAny(char[] anyOf, int st... Normalize        Method                string Normalize(), string Normalize(System.Text.NormalizationForm normal... PadLeft          Method                string PadLeft(int totalWidth), string PadLeft(int totalWidth, char paddi... PadRight         Method                string PadRight(int totalWidth), string PadRight(int totalWidth, char pad... Remove           Method                string Remove(int startIndex, int count), string Remove(int startIndex)
   Replace          Method                string Replace(char oldChar, char newChar), string Replace(string oldValu... Split            Method                string[] Split(Params char[] separator), string[] Split(char[] separator,... StartsWith       Method                bool StartsWith(string value), bool StartsWith(string value, System.Strin... Substring        Method                string Substring(int startIndex), string Substring(int startIndex, int le... ToBoolean        Method                bool IConvertible.ToBoolean(System.IFormatProvider provider)
   ToByte           Method                byte IConvertible.ToByte(System.IFormatProvider provider)
   ...

Ricer Bullshit

Right now I use | Cmder as my Windows shell. Its portable, has some sane defaults, and you can download a version that includes msysgit, so you can carry around unix-like binaries with you on a USB stick. (Obviously for the powershell parts, you wouldn't be needing those.)

If (God Forbid) you want to use the default shell and ```customize``` it to your liking, be my guest. Simply dropping a function in your $profile will allow you to customize your prompt, example below:

   function prompt
   {
       Write-Host ("PS " + $(get-date) +">") -nonewline -foregroundcolor White
       return " "
   }

Surprisingly enough, Write-Host can be used to put foreground colors, background colors, bold text, and many other features at any point anywhere in the shell, so writing scripts to colorize output is easy. The full list of colors can be found in Get-Help Write-Host.

Foreground and background colors can be set in the actual shell with some variables. There's also a built-in properties dialog if you right-click the title bar.

          # OH MY GOD ANON ARE YOU A HACKER?!
          $console = $host.UI.RawUI
          $console.ForegroundColor = "Green"
          $console.BackgroundColor = "Black"
          Clear-Host

Other miscellaneous plugins/editors/colors stuff:

Scripting Stuff

Overall, I'd say Powershell shines as a scripting language over being a shell environment. It works fine in the shell, but its verbose syntax lends itself better towards I've been working on trying to find a way to use Emacs for writing powershell scripts, but so far it isn't going well, and I don't have a great setup yet. If you really want syntax hilighting and IDE-like features, use Powershell ISE, which I discuss in the section Powershell#Ricer Bullshit.

Also make sure your shell can run scripts as discussed in Powershell#Initial Configuration.

Variables and Data Types

Variables in Powershell are prefixed with the $ symbol. There is technically a command to create variables, Set-Variable, but I don't see why - Powershell seems to declare and instantiate on assignment, similar to languages like Python and Ruby. so

   Set-Variable -Name a -Value 1

is equivalent to

   $a = 1;

which seems strange but I suppose there is a purpose, hidden within the documentation for Set-Variable, which probably lies outside the scope of this guide anyways.

Objects

Custom objects can be created and manipulated easily with New-Object, Add-Member, and Get-Member.

    PS C:\> $myobj = New-Object System.Object
    PS C:\> Add-Member -Name "Name" -MemberType NoteProperty -Value "Anon"
    PS C:\> Add-Member -Name "Score" -MemberType NoteProperty -Value 12
    PS C:\> $myobj | Format-List
    Name: Anon
    Score: 12

New definitions of objects can be created with either Add-Type and the -Typedef flag, or by loading pre-defined C# classes into Powershell.

Numbers

Powershell has lots of weird types (hell, everything is an object), but primitives like ints and doubles are pretty tame, and work as one might expect.

   PS C:\> $a = 1
   PS C:\> $a++
   PS C:\> echo $a
   2
   PS C:\> 1 + 3 / 2
   2.5
   PS C:\> (1+3)/2
   2
   PS C:\> 4 % 2
   0
   PS C:\>
   PS C:\> 0.001 + 0.001
   0.002
   PS C:\> 5.0 / 2
   2.5
   PS C:\>

Strings

Strings work pretty much exactly like in Java with a few quirks. The backtick (`) is used for escapes, you can compare and concatenate strings, search within them, index ranges, the list goes on.

   PS C:\> $a = "Hello" + " World!"
   PS C:\> echo $a
   Hello World!
   PS C:\> $a = "Hello `nWorld!" ; echo $a
   Hello
   World!
   PS C:\> $a = "Hello`t`tWorld!" ; echo $a
   Hello           World!
   PS C:\> $a = "Hello ``World``!" ; echo $a
   Hello `World`!

The dollar sign must be escaped inside a Powershell string because variables and code can be inserted directly into strings, like in bash.

   PS C:\> $a = "Hello"; echo "$a World!"
   Hello World!
   PS C:\> echo "I have $(1 + 2) apples."
   I have 3 apples.
   PS C:\> echo "`$"
   $

Other examples:

   # These functions all return true.
   $a.contains("ello")
   $a.startswith("He")
   $a.endswith("!")
   PS C:\> $a.indexof("W")
   7
   PS C:\> $a[0]
   H
   PS C:\> $a[1..4]
   e
   l
   l
   o
   $a.CompareTo("Hello") # Returns 1
   $a.CompareTo("ZZZZZ") # Returns -1
   $a.CompareTo($a)      # Returns 0

Multi-line strings can be created with this syntax: @" "@ . Note that this is really only useful for scripts because in a shell, pressing enter without putting a closing " will allow you to continue writing the command on a new line.

Arrays and Hash Tables

Arrays are declared either purely with commas or with the @( ) syntax, and can contain mixed types.

   PS C:\> $a = $(1, 2, 3, 4)
   PS C:\> $a = 1,2,3,4
   PS C:\> $a = "a",1,"b",2
   PS C:\> $a.Length
   4

They can also be indexed as you would expect and sliced with ranges:

   PS C:\> $a[0]
   a
   PS C:\> $a[1..2]
   1
   b

Hash tables, or dictionaries, are also implemented in Powershell, and work similarly to arrays and dictionaries in other languages:

   PS C:\> $a = @{Key1=1;Key2=2;Key3="YourName"}
   PS C:\> $a.Key1
   1
   PS C:\> $a["Key1"] + 2
   3
   PS C:\> $a["Key3"] + "IsBob"
   YourNameIsBob
   PS C:\>

Of course, hash tables and arrays can be nested.

   PS C:\> $grid = @(0, 1, 2),@(3, 4, 5),@(6, 7, 8)
   PS C:\> $grid.getType()
   
   IsPublic IsSerial Name                                     BaseType
   -------- -------- ----                                     --------
   True     True     Object[]                                 System.Array
   PS C:\> $grid[0][0]
   0
   PS C:\> $grid[0][2]
   2
   PS C:\> $grid[0]
   0
   1
   2
   PS C:\> $student = @{Name="Anon";GPA=3.5;Classes=@("Programming 101","Shitposting 400","Free Software 101")}
   PS C:\> foreach ($class in $student.Classes) { Write-Host "$($student.Name) is taking $class this semester." }
   Anon is taking Programming 101 this semester.
   Anon is taking Shitposting 400 this semester.
   Anon is taking Free Software 101 this semester.
   PS C:\>

Types

Most everything implements .getType():

   PS C:\> $a = "asdf"
   PS C:\> $a.getType()
   IsPublic IsSerial Name                                     BaseType
   -------- -------- ----                                     --------
   True     True     String                                   System.Object
   
   PS C:\> (1).getType()
   IsPublic IsSerial Name                                     BaseType
   -------- -------- ----                                     --------
   True     True     Int32                                    System.ValueType
   
   PS C:\> ("asdf").getType()
   IsPublic IsSerial Name                                     BaseType
   -------- -------- ----                                     --------
   True     True     String                                   System.Object
   
   
   PS C:\> (@{}).getType()
   IsPublic IsSerial Name                                     BaseType
   -------- -------- ----                                     --------
   True     True     Hashtable                                System.Object

and types can be casted and declared with square brackets.

   PS C:\> [int32]$i = 40;
   PS C:\> [int32]$j = "asdf";
   Cannot convert value "asdf" to type "System.Int32". Error: "Input string was not in a correct format."
   At line:1 char:1
   + [int32]$j = "asdf";
   + 13:48, 11 June 2015 (EDT)13:48, 11 June 2015 (EDT)13:48, 11 June 2015 (EDT)Hevnoraak (talk)
       + CategoryInfo          : MetadataError: (:) [], ArgumentTransformationMetadataException
       + FullyQualifiedErrorId : RuntimeException
   PS C:\> [int32](0.0001)
   0
   PS C:\>

Conditionals

In Powershell, if statements are exactly what is expected from a C-style language.

   if ($true -And $true) {
       Write-Host "Horray, boolean logic!"
   }

However comparison operators look like flags or parameters, which is a little weird but not hard to get used to. -And and -Or are obviously your bread and butter:

   $a = $true
   $b = $true
   $c = $false
   $a -And $b # True
   $a -Or $c  # True

If you followed along with those two, -Not is pretty easy also.

  $a = $false
  $b = -Not $a # True
  $c =  -Not 0 # True

-is can be used to check types.

   $a = "HI"
   $a -is [String] # True
   $a -is [Int32] # False

Loops

The simplest type of loop uses the ForEach-Object command (aliased to 'foreach') to cycle through arrays of objects.

   foreach ($i in (1..10)) {
       Write-Host $i;
   }

There are also while, do-while, and do-until loops. The syntax there is pretty cut and dry:

  $a = 0;
  while ($a -lt 10) { Write-Host $a; a++ }
  $a = 10;
  do { Write-Host $a; $a--; } until ($a -eq 0)

(Note: do-until is basically just the opposite of do-while, they work the same way, however it might be cleaner to use do-until in some cases depending on your condition.)

Working with Data

When manipulating data on the command line, you have to always remember the paradigm: Objects, not text. We work with data in structured form instead of in plaintext. This is very evident in how Powershell filters and formats data; instead of using tools like awk, regex and sort, arrays of objects are piped between commands which select, reject, or print them based off of their data members.

Format Commands

Powershell provides several commands for changing the way that it displays data within the shell.

   PS C:\> get-command | ? { $_.Verb -eq "Format" -and $_.ModuleName -eq "Microsoft.Powershell.Utility" }
   
   CommandType     Name                                               ModuleName
   -----------     ----                                               ----------
   Cmdlet          Format-Custom                                      Microsoft.PowerShell.Utility
   Cmdlet          Format-List                                        Microsoft.PowerShell.Utility
   Cmdlet          Format-Table                                       Microsoft.PowerShell.Utility
   Cmdlet          Format-Wide                                        Microsoft.PowerShell.Utility

For now I'm only going to cover Format-Table, Format-Wide, and Format-List.

Format-Table

Running Format-Table on just about anything will produce results which look familiar. I'm not 100% sure about this (need to find a source), but I'm pretty sure Powershell runs every object that goes into stdout through Format-Table before printing it. So just the cmdlet standalone will give you nothing; its the parameters that go into making the magic happen. Look at this example, taken [https://technet.microsoft.com/en-us/library/ee692794.aspx | straight from the horse's mouth]:

   PS C:\> $a = @{Expression={$_.Name};Label="Process Name";width=25}, `
   >>> @{Expression={$_.ID};Label="Process ID";width=15}, `
   >>> @{Expression={$_.MainWindowTitle};Label="Window Title";width=40}
   PS C:\> Get-Process | Format-Table $a
   Process Name                   Process ID Window Title
   ------------                   ---------- ------------
   lsass                                1284
   LSSrvc                               2112
   MDM                                  2240
   notepad                              2348 Untitled - Notepad
   notepad                              3944 Untitled - Notepad
   OUTLOOK                              1192 Inbox - Microsoft Outlook
   powershell                           1348 Script Center

The assignment to $a looks incredibly confusing until you realize that @{} is how Powershell does hash tables and/or dictionaries, and that arrays are defined simply with commas. (Read the Variables and Data Types section if you haven't already). Format-Table simply takes in hash tables which describe how each column of the table is going to look with different keys and values inside the hash table. Format-Table allows you to make really rich representations of what would otherwise be flat and uninteractive data.

Format-Wide

The most boring format command: it simply puts the data in multiple columns to make better use of horizontal screen space, like so:

   PS C:\> get-process
   Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
   -------  ------    -----      ----- -----   ------     -- -----------
        82       7     1076       4216    44            1672 armsvc
       135       9     5800       8480    39     0.09   5320 audiodg
       316      25    15748      23808   200     6.48   2776 ConEmu
       130      11     2952       6520    91     7.09   3660 ConEmuC64
        51       6      964       4008    49     0.02   4936 conhost
        55       7     1404       4628    50     7.23   5828 conhost
       212      12     1792       3756    44             524 csrss
       180      16     2428      38256   202             600 csrss
       314      17     3880      10912    44            1728 dasHost
   PS C:\> get-process | format-wide
   armsvc                ConEmu
   ConEmuC64             conhost
   conhost               csrss
   csrss                 dasHost

Note that this seems to kill your use of Select-Object:

   PS C:\> ps | select-object -Property Name,ID,Handles
   Name        Id    Handles
   ----        --    -------
   armsvc    1672         82
   audiodg   5320        126
   PS C:\> ps | select-object -Property Name,ID,Handles | fw
   armsvc                ConEmu
   ConEmuC64             conhost
   conhost               csrss
   csrss                 dasHost

Format-List

Format-List takes an object or an array of objects and gives a descriptive output of the object's (or objects') properties and values associated with said properties. To be honest, Format-List is kind of a crappy name; the output doesn't really look like a list to me, more like a table. This command is similar to Get-Member but doesn't produce as much output and gives you the data instead of just what data members the object has.

   PS C:\> get-date
   Tuesday, June 9, 2015 8:58:23 PM
   
   PS C:\> get-date | format-list
   DisplayHint : DateTime
   Date        : 6/9/2015 12:00:00 AM
   Day         : 9
   DayOfWeek   : Tuesday
   DayOfYear   : 160
   Hour        : 20
   Kind        : Local
   Millisecond : 922
   Minute      : 58
   Month       : 6
   Second      : 27
   Ticks       : 635694803079228445
   TimeOfDay   : 20:58:27.9228445
   Year        : 2015
   DateTime    : Tuesday, June 9, 2015 8:58:27 PM

Filtering

Where-Object

Where-Object is an incredibly useful command which functions similar to piping output to grep. It filters objects based off of specified conditionals. The ? symbol is an alias to Where-Object.

   PS C:\> $a = 1,2,3,4,15,6,1,2,6,124,68 # Random ints
   PS C:\> $b = $a | Where-Object { $_ -gt 6 } # Select anything greater than 6
   PS C:\> $b
   15
   124
   68

More examples:

   1..100 | ? { -Not ($_ % 2) } # Pick even numbers out of a range
   get-command | ? Noun -eq "Alias" # See all commands which operate on aliases

Select-Object

Select-Object can be used to limit the amount of information Powershell displays or processes.

For instance, if you only care about the names and sizes of a file, the -Property command can be combined with Get-ChildItem to display this information, ignoring other things like LastWriteTime.

  # Displays table of files in directory and their size
  gci | Select-Object -Property Name,Length 

Other useful (and fairly intuitively named) flags to Select-Object include:

  • -ExcludeProperty <String[]> - Removes the specified property from the selection.
  • -First <int> - Displays only the first <int> elements.
  • -Last <int> - Displays only the last <int> elements.
  • -Skip <int> - Skips the first <int> elements.
  • -SkipLast <int> - Skips the last <int> elements.
  • -Unique - Makes the selection into a set with only one of every element.

Command-based Filtering

While Where-Object and Select-Object are really neat, many commands have built-in kinds of filtering, for example the Get-Process command:

   PS C:\> # This is much simpler than get-process | ? Name -eq "firefox"
   PS C:\> get-process -name firefox
   Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
   -------  ------    -----      ----- -----   ------     -- -----------
   1281     185   476300     577120  1557 2,471.92   1792 firefox

If you're curious about a command, check its help page before over-using either filtering tool.

Tips and Tricks

Regular Expressions

Regexp in Powershell is fairly ho-hum, and if you're already familiar with regex in other languages its a breeze. Matching is done with the -Match or -NoMatch operators; -Replace also takes regex as an argument.

   PS C:\> "The Thick Brown Fox" -match "The ..ick Brown \w"
   True
   PS C:\> "The Quick Brown Fox" -match "The ..ick Brown \w"
   True
   PS C:\> "The Quick Brown Fox, The Lazy Dog" -replace "^The","A"
   A Quick Brown Fox, The Lazy Dog
   PS C:\>

Working with Windows

Environment Variables

Environment variables are stored in Env:

   PS C:\> get-childitem Env:
   Name                           Value
   ----                           -----
   ALLUSERSPROFILE                C:\ProgramData
   APPDATA                        <REDACTED>
   CommonProgramFiles             C:\Program Files (x86)\Common Files
   CommonProgramFiles(x86)        C:\Program Files (x86)\Common Files
   CommonProgramW6432             C:\Program Files\Common Files
   COMPUTERNAME                   <REDACTED>
   ComSpec                        C:\Windows\system32\cmd.exe
   FP_NO_HOST_CHECK               NO
   GIT_SSH                        C:\Program Files (x86)\PuTTY\plink.exe
   HOME                           <REDACTED>
   HOMEDRIVE                      C:
   HOMEPATH                       <REDACTED>
   LOCALAPPDATA                   <REDACTED>
   LOGONSERVER                    \\MicrosoftAccount
   NUMBER_OF_PROCESSORS           8
   OS                             Windows_NT
   Path                           C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System3...
   PATHEXT                        .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.CPL
   PROCESSOR_ARCHITECTURE         x86
   PROCESSOR_ARCHITEW6432         AMD64
   PROCESSOR_IDENTIFIER           Intel64 Family 6 Model 60 Stepping 3, GenuineIntel
   PROCESSOR_LEVEL                6
   PROCESSOR_REVISION             3c03
   ProgramData                    C:\ProgramData
   ProgramFiles                   C:\Program Files (x86)
   ProgramFiles(x86)              C:\Program Files (x86)
   ProgramW6432                   C:\Program Files
   PSModulePath                   <REDACTED>
   PUBLIC                         C:\Users\Public
   SESSIONNAME                    Console
   SVN_SSH                        C:\Program Files (x86)\PuTTY\plink.exe
   SystemDrive                    C:
   SystemRoot                     C:\Windows
   TEMP                           <REDACTED>
   TMP                            <REDACTED>
   USERDOMAIN                     <REDACTED>
   USERDOMAIN_ROAMINGPROFILE      <REDACTED>
   USERNAME                       <REDACTED>
   USERPROFILE                    <REDACTED>
   VBOX_MSI_INSTALL_PATH          C:\Program Files\Oracle\VirtualBox\
   windir                         C:\Windows
   
   PS C:\> echo $env:Path
   C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\Windows
   PowerShell\v1.0\;C:\Program Files (x86)\Skype\Phone\;C:\Git\cmd;C:\Git\bin;C:\Program Files\MiKTeX 2.9\miktex\bin\x64\

References