PowerShell
is Microsoft's replacement for the well-worn command prompt. It's pretty slick - definitely puts Windows on par with Unix in terms of shells. Unlike command.com or cmd.exe, it's an actual programming language - with first-class functions, no less. It's got all the usual functional programming language friends - though the names have all been changed ("map" is spelled "foreach-object", "filter" is spelled "where"). What distinguishes it from other scripting languages is the amount of effort that's been put into making Windows features easily available. PowerShell makes it easy to access .Net, COM, WMI, the registry, you name it. Examples:
Here are a couple of examples:
function md5($cleartext)
{
$bytes = (new-object System.Text.UTF8Encoding).GetBytes($cleartext)
$hash = [System.Security.Cryptography.MD5]::Create().ComputeHash($bytes)
[string]::Join("", ($hash | % {$_.ToString("x2")}))
}
Note that ? is an alias for "where" and % is an alias for "foreach-object"
set-alias exist test-path
#standard "which" command, but returns all matches, rather than only
#the first.
function which($p)
{
$dirs = ($env:Path).split(";") | ? { $_.length -gt 0 -and (exist $_)}
$names = @($p) + $env:Pathext.split(";") | % {$p + $_}
$dirs |% {$d = $_; $names | % { join-path $d $_} | `
where {exist $_ } | % {(resolve-path $_).Path} }
}
Notice the extensive use of pipes. PowerShell pipes objects, not text. This is much more like functional programming than like UNIX shells. Let's look at a piping a range of numbers:
PS C:\> 1..5
1
2
3
4
5
PS C:\> 1..5 | foreach {$_ * 2}
2
4
6
8
10
All right so far? These are numbers being passed through the pipeline, not text. Here:
PS C:\> 1..5 | foreach {$_.gettype()}
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Int32 System.ValueType
True True Int32 System.ValueType
True True Int32 System.ValueType
True True Int32 System.ValueType
True True Int32 System.ValueType
What can you do with a number once you've got one?
PS C:\> 1 | get-member TypeName: System.Int32 Name MemberType Definition ---- ---------- ---------- CompareTo Method System.Int32 CompareTo(Int32 value), System.Int32 Com... Equals Method System.Boolean Equals(Object obj), System.Boolean Equ... GetHashCode Method System.Int32 GetHashCode() GetType Method System.Type GetType() GetTypeCode Method System.TypeCode GetTypeCode() ToString Method System.String ToString(), System.String ToString(IFor...
Not too much. How about static methods?
PS C:\> 1 | get-member -static
TypeName: System.Int32
Name MemberType Definition
---- ---------- ----------
Equals Method static System.Boolean Equals(Object objA, Object ...
Parse Method static System.Int32 Parse(String s), static Syste...
ReferenceEquals Method static System.Boolean ReferenceEquals(Object objA...
TryParse Method static System.Boolean TryParse(String s, Int32& r...
MaxValue Property static System.Int32 MaxValue {get;}
MinValue Property static System.Int32 MinValue {get;}
We can also define functions that are pipeline-aware:
PS C:\> function sum() {
>> begin { $total = 0 }
>> process { $total += $_ }
>> end { $total }
>> }
>>
PS C:\> 1..5 | sum
15
Quite a step up from cmd.exe.