PowerShell 101 from a Linux guy


Having spent my last 7 years concentrating mainly on Linux® and related technologies, I spent 3 days with PowerShell and here are the some observations and anecdotes. Why PowerShell? Curiosity for one and I wanted to learn it from a perspective of how to use it in configuration management tools like Chef. As an disclaimer, I’m not an expert in PowerShell and spending 3 days is just scraping the surface but I did learn quite a bit in that time. Also my prediction is that PowerShell will be real force (if not already) in Windows environments. It is a mindset change for several Windows administrators who have grown up on GUIs but that is about to change in the coming years. And if you are Linux administrator, you are likely to feel more comfortable interacting the PowerShell way. I definitely did.

Observations

  • PowerShell was born in 2006 and so it has been around for some time. From the buzz, it seems to be gaining more attention in the last 2-3 years.

  • Just like the Linux shell, if you know your commands and the switches, you can be quite effective. Part of the learning is exploring and getting the feel off the way things are structured and where to look for help.

  • There is a decent naming convention to the cmdlets, which helps in guessing. In my limited trials it has been followed well on the main Windows cmdlets. The convention is “Verb-SingularNoun”. E.g. “Stop-Service” , “Start-Job”, “Get-NetFirewallRule”

  • Auto complete can be annoying for a Linux admin as it does not work the same way as Linux shells but the intent is good and you need to get used to it’s way of working.

  • PowerShell comes in both versions; 32 bits & 64 bits. Non-intuitively, they are structured such that “system32” directory has 64 bit binaries and “syswow64” has 32 bit binaries. Also the version number of the directory inside Windows –> System32 –> WindowsPowerShell is the version the module and not version of PowerShell itself.

  • There are 3 main versions; 2.0 in Windows 2008, 3.0 in Windows 2012, and 4.0 which is was released in Feb 2014. For a new starter 3.0 and 4.0 are the most important releases. Version 3.0 requires .NET framework 4.0 You can find the current version of PowerShell using.

    $PSVersionTable

Man up

Help on powershell is quite good and for the Linux folks “man” works

man <command name>
or
help <command name>

The following pulls all new help files.

update-help

Once done, you can also use specific switches to get things like examples. You can also tell it to open a browser with the help page (assuming you have internet connection on the server and a browser).

help <command name> -example
help <command name> -online

Here are some more examples:-

  • Works with wildcards.

    help *alias*
    help "*"

  • You can also search by parameter names or verbs.

help -Name "*" -Parameter computername
help -Verb "block"
  • An alternative to help is “Get-Command” and is better in some cases. It will also tell you which of them are actual cmdlets and which are aliases. E.g.
    Get-Command -Name ls
    Get-Command -Name Stop-Service
    Get-Command "*resolve*"
    Get-Command -Verb "Block"

Objectification of commands

PowerShell commands generate objects as opposed to text which is what *nix shells tend to do, although some individual *nix commands may have options for things like json. This can be quite powerful, especially since this is implemented quite well across all commands and cmdlets. So you can pipe the objects to other utilities to change formats from lists to tables., csv, etc. Lot of these are available as default and there is also XML but let’s not go there. If you go back to Linux, all of this is text and you end up relying a lot on awk, sed, perl, regex vodoo. *nix admins may argue text is unstructured but simpler in model but having them as objects does lend some good use-cases.

Here are some simple examples:-

Get-Process | Format-List
Get-Process | ConvertTo-Csv
Get-Service | ConvertTo-Json
Get-Process | ConvertTo-HTML | Out-File ps.html

For almost all cmdlets, all properties are not displayed. There is an internal default on the views. Note, the properties are still generated by the cmdlet but it is the view that hides them. You can look for all properties or you can list specific properties.

ls | get-member
Get-Service | Get-Member
"hello world" | Get-Member

Because they are data structures, you can also reference the individual members in the shell which is very handy. For e.g.

(ls).name
(ls).CreationTime
("hello world").Length

Searching and filtering

Because of the objects, you can do some fancy querying and filtering.

  • Using the Select-Object option.

    Get-NetFirewallRule -Enabled True | Select-Object -Property DisplayName,Profile,Direction,Action | Sort-Object -Property DisplayName

  • List files greater than a size and of type “.dll”.

    cd c:\windows\system32
    ls | Where {$PSItem.Length -GT 5000000 -and $PSItem.Name -Like "*.dll"}

  • There are in built respresentations for things like MB, GB. So you can do this.

    cd c:\windows\system32
    ls | where Length -gt  10MB

  • The commands themselves have filtering options and so there are several ways to do the same. The internal filtering is faster than the “where” clause or even the shell’s wildcard evaluation. Here’s an example of this using “Measure-command” which is the similar to “time” on Linux.

PS C:\windows\system32> measure-command { ls | where {$_.Name -like "*.exe"} }

<output truncated>
TotalMilliseconds : 431.5992


PS C:\windows\system32> measure-command { ls *.exe }

<output truncated>
TotalMilliseconds : 141.2392


 PS C:\windows\system32> measure-command { ls -Filter "*.exe" }

<output truncated>
TotalMilliseconds : 27.3214

Variables and loops

  • Variables - You can do simple assignments, arrays, hash tables or the output of another command.

    $value = "hello world"
    $num = @{1,2,3}
    $alerts = @{"warning"=60; "critical"=90}
    $all_procs = (Get-Process)
    $all_procs_json = (Get-Process | ConvertTo-Json)

  • To print them, just type the variable name. “echo” works as well for the Linux guy.

    $value = "hello world"
    $value
    echo $value

  • You can do loops. They also have “awk” like begin and end blocks as well.

    for ($i=0; $i -le 10; $i++) { $i }
    
    Get-Process | foreach -Begin { Get-Date ; "Time to loop"}  -Process { $PSITem.Name ; $PSITem.CPU; "----"} -End {"My loop ended :-)" }

Other points

This is random collection of stuff, I gathered and found useful.

  • History.

    Get-History

  • Print the last command.

    $$

  • Create new aliases. “man” command is an alias to help and you can do this yourself. Now that we have grep. I feel more at home :-)

    New-Alias -Name grep -Description grep Select-String

  • If you don’t want Windows to keep popping up confirmation boxes for several of the commands (Windows likes to do this.), you can do this

    Set-Variable -Name ConfirmPreference -Value Low
    #or
    Set-Variable -Name ConfirmPreference -Value None

  • Piping to “more” is not ideal as it causes PowerShell to evaluate the whole command before sending it. This is better.

    help "*network*" | out-host -paging

You can alias “out-host” to something more familiar and if you want “less”, there is an extension at Code Plex.

  • Several commands support -ComputerName and so you can run it on remote computers. You can also pass a comma separated list.
    Get-Service -ComputerName <server1,server2>

You can search help for cmdlets that support this parameter.

help * -parameter ComputerName

  • Providers - An interesting take on making some of the services available as a File system.

For e.g. you can access the registry and also make changes to it. “Get-Providers” will show the list of available providers.

Get-Providers
cd HKLM:
ls .\SOFTWARE\Microsoft\Windows\CurrentVersion

Quick reference

Bash/Linux PowerShell
ls ls
mv mv
cp cp
pwd pwd
rm rm
cat cat
grep search-string
echo echo
var=0 $var=0
df gdr or Get-PSdrive
wc measure-object
ps ps
find gci
diff diff
kill kill
time measure-command
if [condition] then something fi if (condition) { something }
-e file Test-Path file
for ((i=0; i < 10; i++)) ; do echo $i ; done for ($i=0;$i -lt 10; $i++) { echo $i }
-e file Test-Path file
for ((i=0; i < 10; i++)) ; do echo $i ; done for ($i=0;$i -lt 10; $i++) { echo $i }

References and further reading

Learn more about IT Transformation

Use the Feedback tab to make any comments or ask questions. You can also start a conversation with us.

post avatar
Sriram(Sri) Rajan

Share this information: