PS for .NET devs part 2: Comparing the PowerShell language to C#

Posted on Nov 14, 2011

In my previous posts in this series I discussed why you should care about PowerShell and I pointed to some resources to help you get started with PowerShell. This post will describe the syntax of the PowerShell language by comparing it with the syntax of C#. Recently the PowerShell language specification was released under the community promise, so if you want to learn everything there is to know about the PowerShell language look it up.

To summarize this post: When translating a piece of C# code to PowerShell take what you would normally write in C#, remove all the explicit typing and add a few $’s here and there. The comparison is mostly presented in a tabular form showing the C# syntax in the first column and the equivalent PowerShell syntax in the second, followed with a description of the particular language construct in the last column. Enjoy.

Comments

C#PowerShellDescription
//#single line
/* ... */<# ... #>multi line
///single line documentation comments

Comment documentation keywords

PowerShell is also blessed with comment-based help but because it does not have any formating keywords and does not focus on types, a lot of the corresponding keywords have no equivalent in the PowerShell column. PowerShell supports more keywords than the ones listed below for the entire story please use PowerShell’s built in help: help about_Comment_Based_Help or the online documentation:

C#PowerShellDescription
<c>Set text in a code-like font
<code>Set one or more lines of source code or program output
<example>.EXAMPLEIndicate an example
<exception>Identify the exceptions a method can throw
<include>.EXTERNALHELPIncludes XML from an external file
<list>Create a list or table
<para>Permit structure to be added to text
<param>.PARAMETERDescribe a parameter for a method or constructor
<paramref>Identify that a word is a parameter name
<permission>Document the security accessibility of a member
<remarks>Describe a type
<returns>.OUTPUTSDescribe the return value of a method
<see>.LINKSpecify a link
<seealso>.LINKGenerate a See Also entry
<summary>.SYNOPSISDescribe a member of a type
<value>Describe a property
.NOTESAdditional information about the function or script
.DESCRIPTIONA detailed description of the function or script
.INPUTSThe inputs that can be piped to the function or script

Literals

Literals are the same as in C# with a few minor differences:

  • In PowerShell the backtick (`) is the escape character: PS>"Quotes need to be escaped `""
  • PowerShell does not have char literals to create one you have to use a cast: [char]"a".
  • PowerShell multi-line strings also begin with the @" it however has to be followed by a new line, furthermore the end mark is a "@ which has to be put at the beginning of the line.
  • Array literals are created using the array operator ,. So "Fred","Barney" creates on array containing 2 strings.
  • PowerShell distinguishes single quoted '' and double quoted "" string literals the former causes the string to be interpreted verbatim while the later is subject to string interpolation. Here’s an example:
1
2
3
4
PS>"my $PSCulture is dutch"
My nl-NL is dutch.
PS>'my $PSCulture is dutch'
My $PSCulture is dutch.
  • PowerShell supports HashTable literals of the form: @{ <name> = <value>; [<name> = <value> ] ... }. Below you can see that HashTable literals can be split across multiple lines in which case the semicolons (;) after the name-value pair can be omitted leaving a nice and readable HashTable behind.
1
2
3
4
5
6
7
PS>$table = @{ a=37; b=42;}
PS>$ttable = @{
>>a=37
>>b=43
>>}
>>
PS>

Variables

In PowerShell variable declarations don’t require explicit typing, they do however have to be prefixed with a $.

1
2
PS>$now = [DateTime]::UtcNow
PS>$message = 'hello'

Being a .NET developer you’re probably wondering how you can create objects in PowerShell. There is no new keyword but there is a New-Object Cmdlet. It can for example be used like this:

1
2
3
4
PS>$dateofbirth = New-Object DateTime -ArgumentList 1972,7,12
PS>$feeds = new-object -Com Microsoft.FeedsManager
PS>$feeds.IsSubscribed("http://basbossink.github.com/atom.xml")
True

To have a little bit more brevity in the shell you don’t have to specify the entire full name of the type. PowerShell has some built-in type accelerators so for instance in the case of System.DateTime you can leave of the System namespace part. See this StackOverflow question for some extra references about the subject. As you can see the New-Object Cmdlet can also be used to create COM objects see help New-Object for more details or look at the online documentation.

Operators

The arithmetic and assignment operators are the same for C# and PowerShell the differences start with the comparison operators the familiar > and friends are replaced with a - followed by an abbreviation for the comparison. This was done to keep the meaning of > for redirection as all system administrators now it from dos and POSIX shells.

Apart from this table above there are a couple of extra operators that have no C# equivalent:

  • Redirection operators: >, >>, 2>, 2>&1
  • Comma operator: , Creates an array.
  • Split and Join operators: -split,-join To divide and combine substrings
    1
    2
    3
    4
    5
    
    PS>1,2,3 -join '*'
    1*2*3
    PS>$env:PATH -split ';'
    %SystemRoot%\system32\WindowsPowerShell\v1.0\
    
  • Call operator: & Run a command, script, or script block.
    1
    
    PS>& 'C:\Program Files (x86)\GNU\GnuPG\sha256sum.exe' test.iso
    
  • Dot sourcing operator: . Runs a script so that the variables, functions defined in the script are part of the calling scope.
  • Static member operator: :: Used to call static method or retrieve static properties of a .NET Framework class.
    1
    
    [Math]::Sin(([Math]::PI)/2)
    
  • Range operator: .. Represents the sequential integers within the given upper and lower boundary.
    1
    2
    
    PS>1..10 -join ','
    1,2,3,4,5,6,7,8,9,10
    
  • Format operator: -f The following two pieces of code are equivalent (starting with C#):
    1
    
    Math.PI.ToString("{0:0.00}")
    

    1
    
    "{0:0.00}" -f [Math]::PI
    
  • Subexpression operator: $() Returns the result of one or more statements. Very handy in string interpolation like
    1
    2
    3
    
    
    PS>"This machine has $([Environment]::ProcessorCount) cpu's"
    This machine has 2 cpu's
    
  • Array subexpression operator @() Returns the result of one or more statements as an array.

Selection Statements

PowerShell supports the if-else and switch statements. The if-else differs only in the fact that PowerShell has a elseif keyword where C# uses else if.

In PowerShell the switch statement has more functionality compared to C# since it supports switching on regular expressions and wildcards when the values supplied let themselves be converted to strings. Again use help about_Switch (or look here).

Iteration Statements

Even though it’s not explicitly mentioned in the table above PowerShell also supports the familiar break and continue keywords. See help about_break (or here) and help about_continue (or here) for details. When using ForEach-Object the Automatic Variable $_ represents the current item, see help about_Foreach for details.

Exception Handling

Since version 2 PowerShell supports the C# try-catch-finally syntax besides the earlier introduced trap keyword, which can be viewed as a catch block with an implicit try for the surrounding scope. PowerShell also supports throw, the difference being that any expression can be thrown. The expression in the throw syntax is optional, this reminds me a bit of the Perl die function.

Functions

Functions in PowerShell are quite a different beast when compared to C#. At first glance there are many similarities, both languages support positional parameters, keyword parameters and optional parameters. The extra benefit in the case of PowerShell in my opinion is, the ability to use pipeline parameters. Lets look at an example:

1
2
3
4
5
6
7
8
9

function Get-SumOfSquares {
    begin { $result = 0 }
    process { $result += $_ * $_ }
    end { $result }
}
1..25 |
ForEach-Object { Get-Random -Maximum 100 } |
Get-SumOfSquares

Here you can see the filtering of the pipeline input in a way that reminds me of Awk, the begin and end syntax specifically. The begin and end blocks mean exactly what you think they mean. The process block gets called by PowerShell for each value received from the pipeline. Where $_ has the value of the Current value as in the value of the Current property when using the IEnumerator interface. Since version 2 a lot of functionality was added to provide extra functionality to functions, the so called Advanced Functions see help about_Functions_Advanced for details this includes stuff like declarative parameter validation, specifying parameter sets, aliases and a brief help message for parameters. Elaborating on the earlier Get-SumOfSquares example a full blown implementation could look something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16

function Get-SumOfSquares {
    Param(
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   HelpMessage="An array of integers." )]
        [Alias("IN")]
        [int[]]
        $InputObject
    )
    $result = 0
    $InputObject | ForEach-Object {
        $result += $_ * $_
    }
    $result
}

After pasting this in the PowerShell console an example usage might look like the screenshot below.

Get-SumOfSquares example interaction

Epilogue

This is my brief summary of the syntactic differences between C# and PowerShell. I hope this can help you with coming to grips with PowerShell. Next time we’ll look at how easy it is to work with XML in PowerShell and munge a large MSBuild file with a small script.

References