Programblings

Rambling about programming and life as a programmer

Discover Powershell

Update: This article has has a new home on programblings.com. Go to the article.
Comments are closed here but still open there :-)

For ages now, Windows users have been yearning for a better console and a good scripting language for their operating system. I’m not going to get into the history of MS’ attempts at fixing this (VBScript and WSH friends). Instead I’ll delve right into what seems to be the (bright) future of scripting under Windows: Powershell.

In this tutorial I’ll try to explain briefly what Powershell is and give some examples. This is not meant to be a complete tutorial, however: for that you’ll have to scroll all the way down to the references section.

Powershell (originally known as Monad) is the future of Windows scripting. It will be bundled with Windows Server 2008 and probably the next desktop versions as well (maybe even Vista SP1?) Anyway, meanwhile Powershell can be downloaded for use with XP SP2, Vista, and Server 2003.

For now PS does not replace the console you know and hate. It only styles it a little bit. Skeptics could remind me that a dog with lipstick is still a dog. I’d say read on and decide for yourself after you’ve given Powershell a try. So here it is:

Powershell console (empty)

Tremendous, it’s blue instead of black! This is all very well, but not too convincing yet, I guess. Let’s see in more detail what there is to Powershell.

Basics

Before I dive into features, I’d like to quickly cover some basics. First of all, go Get Powershell, and then grab MS’ Powershell quick reference and print it.

Variables

$variable = <expression>

Strings

“a string that will expand a $variable”

‘a string that not will expand a $variable’

Paths

Both \ and / are accepted where paths are expected. This also means that parameters don’t start with a / anymore, they start with a -.

You can now navigate to UNC paths, as opposed to the old console:

cd \\someserver\someshare

Case sensitivity

PS keeps with Windows’ traditional way of being case insensitive. This is valid for the file names as well as the commands/parameters/arguments.

Keeping it quiet

dir > $null

Being verbose (you, that is)

#This is a comment!

There are no multiline comments but you can use multi-line strings. It’s patchy but it works (don’t use @” and “@ for multi-line comments, see Strings a couple lines up to know why).

@'
loooong comment
'@ > $null

“New” navigation trick

Need to do a couple of things in a directory then get back? The days of saving the current directory manually are over:

pushd 'c:\Windows\System32'

#Do evil stuff

popd

Actually I just realized that the current console also supports this! Shame on me :-)

Control flow

The usual suspects are there, look at the Quick Reference. While you’re there, look at “How to Make Comparisons”, as well.

Finding out more

Along the way, if you’re eager to find out more about what’s I’m talking about, you can always use the following commands.

Getting help

help <commandname>, help <aliasname> or the shorthand <command> -?.

All will bring up basic help with all the command’s parameters. If you need more information, you can append -detailed or -full to get a more complete explanation, examples and so on.

If you need help with concepts (other than commands) about Powershell, you might have luck with about_

help about_regular_expression

help about_reg*

help about_*

Members of an object

When you’re wondering what kind of object you’re dealing with, you can always use the command Get-Member. It will start by displaying the class of the object and then display all its members.

$var = "some string"

$var | Get-Member

Features

Powershell works hard to make Windows and Posix users feel right at home

Powershell syntax uses aliases. So for example dir and ls will work (both are aliases for Get-ChildItem). However, in order to minimize nightmares all around the world, the respective aliases’ original arguments are not necessarily preserved. Instead you’ll have to check PS’ new way of doing things (try the help mentioned earlier). To keep the same example, instead of writing

dir /s *.txt

or

ls -R . *.txt

With PS one would either type:

ls . *.txt -recurse

or dir . *.txt -recurse

or to completely swallow the PS pill:

GetChild-Item . *.txt -recurse

Powershell piping is object-oriented

Wow! So PS event has some (20 years old) buzzword compliance? (That was my first thought, at least.) Seriously, this has some nice advantages over returning plain text. Let’s remember some of the side effects of commands returning text and piping text between commands:

  • On most individual commands, lots of arguments exist only to format the text (ls -lb), rather than to modify the behavior of the command (e.g. flat vs recursive);
  • You’ll sometimes have to resort to regexes to understand the text blob a command returns, introducing accidental complexity to your scripts (or yellow code).

Now let me explain with a couple of examples what is meant by piping objects.

First of all, it must be mentioned that all objects have a default representation. So a simple dir would still simply display the list of files in the current directory.

Behind the scenes, however, the command dir returns a list of objects. If you want to format it differently, you can pipe it to Format-List, Format-Table, Format-Wide or Format-Custom (fl, ft, fw or fc):

dir | fl Name, CreationTime, LastAccessTime

You can put the result of your dir in a variable:

$myFiles = dir

Now $myFiles is an array of objects, likely containing instances of System.IO.FileInfo and System.IO.DirectoryInfo.

You can reuse that array and iterate over it, filter through it, sort it and all kinds of neat stuff like that. $myFile[0] gets you the first result of the array. Here’s an example of filtering :

Get-Alias | where-object {$_.Definition -match 'Get-Childitem'}

That’s a mouthful! Let’s explain what all this is. Get-Alias returns all aliases currently defined and we filter them with Where-Object to display only Get-ChildItem‘s aliases. Namely dir, ls and gci. The Perl-like $_ refers to the object being handled at each iteration. We check that its Definition matches 'Get-ChildItem' with the -match parameter , which accepts a regex.

Now we sort:

Get-Alias | Sort-Object #Sorts by name

Get-Alias | Sort-Object Definition

Let’s do a quick example of foreach as well, before moving on:

dir | foreach-object { $totalsize = $totalsize + $_.Length }
$totalsize

Note: since $totalsize didn’t already exist, it’s been initialized to 0.

Powershell is very well integrated with Windows

The registry

Here’s one feature that made me smile from ear to ear: you can browse and read the registry like you browse and read files on your filesystem.

cd hklm:software\Microsoft

dir

This approach is Ok for exploration. However I find that reading the value directly is often enough:

$key = Get-Item 'hklm:software\Microsoft\Internet Explorer'

Now we can get/set values

$key.GetValue('Build')

Or work with subkeys

$subkey = $key.OpenSubkey('International')

Processes and services

You can also see what’s happening on the computer:

$processes = Get-Process

$processes

To display all properties of a given process

$processes[0] | fl *

To find processes with a specific characteristic

Get-Process | Where-Object { $_.Product -match 'Microsoft' }

or

Get-Process | Where-Object { $_.Threads.Count -gt 20 }

If you want to see what services are configured:

Get-Services

Which ones are running only:

Get-service | Where-Object {$_.Status -eq 'Running'}

You can also manipulate them

Get-Service 'wuauserv' | fl *

Stop-Service 'wuauserv'

Start-Service 'wuauserv'

File formats

A couple of nice file formats are supported by default.

txt

Of course!

dir | Out-File 'dir.txt' -noClobber

dir > 'dir.txt'

dir >> 'dir.txt'

Note: Out-File is just for when you need to use the command’s additional parameters.

csv

dir | Export-Csv 'dir.csv'

$dir = Import-Csv 'dir.csv'

Other file formats

You can also work with other file formats, such as XML, with Powershell. But I guess for an introduction it’s starting to get a little too deep :-)

Other specific uses

For administrators

You can use Powershell to help with administrations tasks:

- User and group management

- Network administration tasks and monitoring using WMI (e.g. remote installs, system restores, etc.)

For developers

Hold on to your hats, fellow developers: it’s possible to instantiate .Net and COM objects directly from the Powershell console.

If you’ve never worked with a language that has an interactive console (e.g. Ruby, Python), maybe you haven’t fallen off you chair yet.

I think an interactive console is a great way to explore a language or some of its functionalities, like for instance an API class or method you’ve never used before.

Some examples:

$ts = new-object System.TimeSpan(16, 05, 0)
$ts

Hmmm, is that really a .Net object? Let’s see:

$ts | Get-Member

Nice, we’ve got all our .Net methods! No more need for a ‘Dummy’ project to fiddle with all those obscure API bits!

Here are a couple more usage examples.

Calling a static method:

$n = [System.DateTime]::Now

Id check:

$n | Get-Member

Using an Enum is similar to accessing a static member:

$d = new-object System.DateTime(1999,12,31,23,59,59, [System.DateTimeKind]::Local)

Instanciating an object with its parameterless constructor:

$st = new-object System.Diagnostics.StackTrace

Powershell is also extensible. It’s possible to create Cmdlet’s (the horrible name they gave Powershell commands) and assign aliases. A Cmdlet would be Get-ChildItem, while its aliases are dir, ls and gci.

Finally, Powershell is powerful enough to automate most project automation tasks, such as automated builds and other continuous integration tasks.

Creating and running your own scripts

To wrap it all up, I feel I need to give a couple of pointers on how to create scripts per se.

Extension

.ps1

What more can I say? :-)

Security

Probably as a consequence of being bit pretty hard with all vbs exploits in the past years, Microsoft made sure that by default, after installing PS you were still as safe as before. It’s always nice not to be instantly vulnerable to a whole new class of exploits when you install new tools.

The first security measure is that by default, ps1 scripts will not be executed just by invoking them by name (as opposed to batch files, for example). If you want to call a script, it’s with the explicit invocation of the interpreter:
powershell.exe your_script.ps1

More importantly, Powershell supports the signing of scripts as well as execution policies. You have 4 choices of execution policies: Restricted (default), AllSigned, RemoteSigned and Unrestricted.

Restricted mode means it won’t run scripts at all. So as any good developer would do:

Set-ExecutionPolicy Unrestricted

Now you can start your scripts from the console.

.\myscript.ps1

Yes, the .\ part is mandatory now. Another security flaw fixed.

If you really want that, of course, you can associate .ps1 to the powershell.exe interpreter, which should be in your path.

Arguments

To top it off, you can access the arguments passed to your script with the $args array.

$args | Foreach-Object { $_ }

Conclusion

I first stumbled upon the very good “Learn Powershell in your Lunchbreak” series, and boy, it’s quite a mouthful! It covers a lot of ground and goes quite deep into a lot of uses for Powershell. A must-read for anyone interested in learning more about Powershell.

My goal with this article was to offer a more gentle introduction to Powershell and maybe even open eyes that were once closed to this new and very powerful tool for the Windows platform. Let me know if I succeeded or failed miserably :-) If you have suggestions, questions or corrections, they are welcome as well.

References

Some Powershell blogs

21 Responses to “Discover Powershell”

  1. [...] Discover Powershell [...]

  2. Thanx!

  3. webmat said

    Not worth taking the time to rewrite part of the article, so here’s a quick rundown on how to instantiate .Net objects from Powershell and have an equivalent to irb (Ruby).

    Instantiation of an object:
    $ts = new-object System.TimeSpan(16, 05, 0)

    To see what it has in store, as usual:
    $ts | Get-Member

    To use a static method directly:
    $n = [System.DateTime]::Now

    $n | Get-Member

    So now I don’t need a dummy solution to fiddle with new classes anymore! :-)

  4. webmat said

    To use an enum value, the trick is similar to using a static method. Here’s an example with the DateTimeKind enum:

    $d = new-object System.DateTime(1999,12,25,23,59,59, [System.DateTimeKind]::Local)

  5. webmat said

    To instantiate an object whose constructor has no parameter, simply drop the parentheses:

    $st = new-object System.Diagnostics.StackTrace

  6. Chui said

    err, don’t put destructive jokes in your guide. please.

  7. webmat said

    You’re right, I replaced the rm example with an ls example :-)

  8. For ages now, Windows users have been yearning for a better console and a good scripting language for their operating system.

    Huh? Windows users are Windows users because they DON’T want to have to deal with a console. I’ve heard from Windows users for years that a console is too hard to use and everyone else should get with the times and go GUI. Now we are being marketed the exact opposite. It reminds me of the diamond cartel which used to tell us that the purest most perfect diamond was the best and then perfect man-made diamonds came along and now we are told that impurities and imperfections give a diamond character. If Unix didn’t have a shell would ME even be considering re-adding one to Windows? If they are trying to compete with Unix it is going to be tough going because the Unix shell is integrated at all levels throughout the OS via common conventions like stdin, stdout, etc. and used to control system startup, shutdown, etc. I’ll be impressed if Windows ever achieves that level of integration with its shell. Then I’ll have to ring up the folks who just a few years earlier were panning on shells. :) First a TCP/IP stack, then multi-user, then remote access, now a shell…someday it’ll be (as good as) Unix! ;)

  9. CK said

    I believe that Set-ExecutionPolicy RemoteSigned gives you a little more security, while still allowing you to run unsigned local scripts.

  10. webmat said

    Tracy: I agree with you that most Windows users don’t care about the console. Powershell is a great tool for developers, admins and power users, though. And arguably maybe even these classes of Windows users don’t care much for the console, but I would guess that’s mostly due to the quality of the console they used to have at their disposal ;-) If they’re shown what can be done with PS, they might change their mind.
    For example Cygwin users might be a bit cynical about Powershell, but when they do try it, they might notice that it solves most of what they try to accomplish with Cygwin. And it’s a lot better integrated with Windows ;-)
    Oh, and nothing stops a Windows power user to make a tool to resize photos, either. All the .Net stack is at their disposal directly in their scripts or they can create Cmdlets with C# as well :-)

  11. webmat said

    CK: Thanks for the pointer, I’ll have to try that!
    I admit I took the easy choice here ;-)

  12. webmat said

    For a free Powershell editor with code completion and syntax highlighting, check out
    http://www.powergui.org

    For more blogs about Powershell, look at

    Dmitry’s PowerBlog: PowerShell and beyond
    http://dmitrysotnikov.wordpress.com/

    Posholic
    http://poshoholic.com

    MSGoodies
    http://msgoodies.blogspot.com/search/label/PowerShell
    Since I couldn’t figure out how to only follow the Powershell label in my feed, I made a Yahoo Pipe for it as well:
    http://pipes.yahoo.com/pipes/pipe.run?_id=2jHdwjh_3BGdkDNcyjUFzw&_render=rss

    Keith Hill’s Blog: PowerShell
    http://keithhill.spaces.live.com/category/PowerShell

    If you find other interesting sources, feel free to share them here!

  13. webmat said

    Someone on Reddit mentioned this project. I’ll have to give it a try with Powershell.

    http://sourceforge.net/projects/console

  14. webmat said

    I just updated the “For developers” section with the bits I had included as comments a while ago.

  15. [...] is the Direct Link to the Post. digg_url = [...]

  16. [...] Discover Powershell « Programblings (tags: scripting shell windows) [...]

  17. craxaffinorgo said

    To me it is necessary to find

  18. [...] without further ado, Discover Powershell (it’s an [...]

  19. [...] Here is the Direct Link to the Post. [...]

  20. [...] The basics are coveraged better than I could possibly do webmat’s blog. [...]

  21. [...] Discover Powershell « Programblings (tags: powershell windows scripting) [...]

 
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: