Category: PowerShell

PowerShell and Windows 7

I should have posted this long ago, but here it is. I did not manage to install PowerShell 2.0 on Windows 7. Windows complained about a newer version that already was supposed to exist on the system. And yes, just open the Run dialog (Win+R) and type powershell, and there it is.

To start the graphical version, type powershell_ise in the Run dialog.

If you want to be able to start it without doing any typing, you can right click on it in the taskbar, and select Pin this program to taskbar.

How to download a file, the PowerShell way

If you want to try this out, please read this first. There, I did an upload using FTP with network credentials (username and password). This time, I want to show how to download a file using HTTP. I am using PowerShell 2.0.

#Load the System.Net namespace.
[System.Reflection.Assembly]::Load
("System.Net, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")

#Load the System.IO namespace.
[System.Reflection.Assembly]::Load
("System.IO, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")

#The target filename on the local system.
$Target =  "C:\downloaded.wav"

#Full source path.
$RemoteSource = "http://www.mysite.com/myfile.wav"

#Use the static method Create to create a web request.
#Pass the destination as an argument, and cast it to a HttpWebRequest.
$R=[System.Net.HttpWebRequest][System.Net.WebRequest]::Create($RemoteSource)

#If not anonymous requests are allowed, you can
#add a System.Net.NetworkCredential to the Credentials
#property of the request object ($R).

#What kind of method it will represent? A http request.
$R.Method = "GET"

#Execute and grab the response object (System.Net.WebResponse).
$Resp = $R.GetResponse()

#Get a reference to the response stream (System.IO.Stream).
$RespStream = $Resp.GetResponseStream()

#Create a stream to write to the file system.
$Wrt = [System.IO.File]::Create($Target)

#Create the buffer for copying data.
$Buffer = New-Object Byte[] 1024

#In an iteration...
Do {

#...attemt to read one kilobyte of data from the web response stream.
$BytesRead = $RespStream.Read($Buffer, 0, $Buffer.Length)

#Write the just-read bytes to the target file.
$Wrt.Write($Buffer, 0, $BytesRead)

#Iterate while there's still data on the web response stream.
} While ($BytesRead -gt 0)

#Close the stream.
$RespStream.Close()
$RespStream.Dispose()

#Flush and close the writer.
$Wrt.Flush()
$Wrt.Close()
$Wrt.Dispose()

Happy coding!

Calling a function

The parenthesis are important when you are calling a function in PowerShell. The parenthesis tells PowerShell that you intend to call the method, not acquire a reference to it. This code illustrates this.

$random = New-Object System.Random
$response1 = $random.next
$response2 = $random.next()

The $response1 variable will contain a reference to the function next, and the $response2 variable will contain an integer value, like 1611459187. The type of $response1 is System.Management.Automation.PSMethod and the type of $response2 is int32. If you want to use the reference to the function, use its Invoke method:

Write-Output $response1.Invoke()

To call static function, type the path to the function (namespaces and classes) followed by a double colon (::), and then the name of the function. Parenthesis are required, even if the function doesn’t take any parameters.

[System.Reflection.Assembly]::Load
("System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")

[System.Windows.Forms.MessageBox]::Show("Hello!")

How to upload a file, the PowerShell way

If you haven’t activated scripting in PowerShell, do that first.

To access the System.Net namespace, I have to load it using the Load method (System.Reflection.Assembly.Load). To know what version and public key you must refer to, check the System.Net item in Explorer (C:\Windows\assembly).

This is the code, directly converted from the Visual Basic version:

#Load the System.Net namespace.
[System.Reflection.Assembly]::Load
("System.Net, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")

#The full path to the source file.
$Source =  "C:\MyFiles\SourceFile.txt"

#The full destination path (will be created).
$Destination = "ftp://www.myserver.com/myfolder/destination.txt"

#Use the static method Create to create a web request.
#Pass the destination as an argument, and cast it to a FtpWebRequest.
$R=[System.Net.FtpWebRequest][System.Net.WebRequest]::Create($Destination)

#Tell the request how it will login (using a NetworkCredential object)
$R.Credentials = New-Object System.Net.NetworkCredential("myUsername", "P@ssw0rd")

#...and what kind of method it will represent. A file upload.
$R.Method = "STOR"

#Here I use the simplest method I can imagine to get the
#bytes from the file to an byte array.
$FileContens = [System.IO.File]::ReadAllBytes($Source)

#Finaly, I put the bytes on the request stream.
$S = $R.GetRequestStream()
$S.Write($FileContens, 0, $FileContens.Length)
$S.Close()
$S.Dispose()

This code gives a good example on PowerShell syntax and it clearly illustrates the power and versatility of the language.

I used Graphical Windows with PowerShell 2.0 to do this example.

This example shows how to download a file using PowerShell.

The splat operator

I must admit that I am not completely up to date with PowerShell 2.0 (PS2), even though the CTP (community technology preview) has been out for a while. The first thing that you will notice, is that you are no longer bound to the old console window. PS2 comes with a graphical editor that separates runspaces in tabs, and each tab has three sections; a script editor, an output window and a direct window that executes what you type, in the same way that the console window did. Since this is a WPF application (as apposed to a console application), you can use the regular cut and paste features in Windows.

Some of the other new features includes the splat operator, remoting, Add-Type and ScriptCmdlets.

The splat operator allows you to pass multiple pairs of keys and values to one single parameter.

This is the basic idea of hash tables in PowerShell:

Here, I want a function that can take one parameter. That parameter will be a hash table. The only line in the function write outs the value that is assigned to the key “test”:

function splatMe($arg) { write-output $arg["test"] }

When that function is added to the runspace, I create a hash table using the splat operator (@):

$hello = @{"test"="1"; "tjo"="2"}

I can now call the splatMe function, passing $hello (my hash table) as a parameter like so:

splatMe $hello

The result will be “1″. I also have the option of creating the hash table on the fly:

splatMe @{"x"="hello"; "test"="Mr. Bean"; "z"="yepp!"}

The output will be “Mr. Bean”.

Remoting allows execution of cmdlets and scripts on remote machines.

Add-Type lets you compile and use fragments of code from any .NET language.

ScriptCmdlets lets you build new cmdlets using PowerShell script, as regular cmdlets had to be written in Visual Basic or C# and had to be compiled.

Execute a cmdlet or PS1 script from Visual Basic

The cmdlets in PowerShell can easily be executed from within Visual Basic. I have done this in a few Visual Basic 8 projects, and the code for doing this from Visual Basic 8 can be somewhat ugly, but in Visual Basic 9 (and .NET Framework 3.5) it is very straight forward. You will need a reference to System.Management.Automation. If you don’t have it, you will get it when you install the Windows SDK for Windows Server 2008 and .NET Framework 3.5 from here. System.Management.Automation.dll installs to C:\Program\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0.

The Runspace object will host the Pipeline object, and the Pipeline object is used to execute cmdlets or PS1 scripts.

Some preparations: I have activated script execution and I have created a script file (C:\script.ps1) that contains one simple line: Write-Output 10+2

'Create the runspace.
Using R As System.Management.Automation.Runspaces.Runspace = _
System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace()

   'Create the pipeline
   Using P As System.Management.Automation.Runspaces.Pipeline = R.CreatePipeline()

      'Open the runspace.
      R.Open()

      'Create each command (in this case just one)...
      Dim Cmd As New System.Management.Automation.Runspaces.Command("C:\script.ps1", True)

      '...and add it to the pipeline.
      P.Commands.Add(Cmd)

      'Execute the commands and get the response.
      Dim Result As System.Collections.ObjectModel.Collection(Of _
      System.Management.Automation.PSObject) = P.Invoke()

      'Close the runspace.
      R.Close()

      'Display the result in the console window.
      For Each O As System.Management.Automation.PSObject In Result
         Console.WriteLine(O.ToString())
      Next

   End Using
End Using

Output: 12

PowerMigrator for PST

This post reveals the concept of PowerMigrator for PST, a software designed for flawless migration of mailboxes from PST-files to Microsoft Exchange. Jesper Ståhle is the conceptual designer and architect and I programmed this under his supervision. To match the minimum requirements of PowerShell, we used .NET framework 2.0 to build this application. The system requirements of the whole migration is monitored, and the status is displayed in the main GUI of PowerMigrator to the right, as shown in this picture:

The main GUI of PowerMigrator for PST.

Accounts can be imported or added directly to the application.

The context menu in the account list.


The file menu. Among other things, from this menu, you can import a list of accounts into PowerMigrator.

To import accounts, select Import SamAccountName list from the file menu, to display the Import SamAccountName list dialog. From here you can load a text file with accounts who’s mailboxes you want to import to Microsoft Exchange.

The job menu.


The view menu.


The tools menu gives access to the options of PowerMigrator for PST, and the log. The log displays all events of the current session, and has the ability to save the items as a text file.

What is PowerMigrator for PST?

  • PowerMigrator is simply a batch management tool for bulk imports of PST-files to Exchange mailboxes.
  • PowerMigrator is also a GUI for PowerShell management of Exchange mailboxes. Allthough it is customized for the Import-Mailbox command, you can use the application to launch PowerShell scripts with the built-in variables in any way you like!

When will PowerMigrator for PST come in handy?

  • If you are facing a bulk import of PST-files to Exchange Mailboxes (E.g mail data migration scenarios from POP3-based e-mail systems to Exchange 2007).
  • If you are facing a bulk change of mailbox permissions where batch management is a must-have (e.g if a big number of users are spread out all over the OU-structure with no common attributes, and you want them to be in the same batch).
  • If you are facing any kind of PowerShell mailbox management scenario in Exchange where you need to have full control over the process. Make PowerMigrator your management console for any mailbox management task.


Migrate PST-files to Exchange 2007, easy as this:

  • Either have PowerMigrator create mailboxes for selected users (imported list of users or manually added group of users)…
  • Or create the mailboxes yourself and import the list of users straight from an EMC export file of the mailboxes (EMC\Recipient Configuration\Mailbox\Export List…)
  • Mark the users you wan’t to run in the next batch. Either set individual settings for the users or let the global settings decide settings such as where the PST-file can be found or in which database the users mailbox shall be created.
  • Start the job and lean back while PowerMigrator generates individual PowerShell-code for each mailbox and executes it.
  • When the batch is done, you return to PowerMigrator where you can review the success rate and logs.
  • Keep going with the next batch until your bulk import of PST-files are ready and your users are on Exchange 2007 with full mailbox history!


Benefits of using PowerMigrator instead of hacking your own PowerShell-code:

  • Batch management is possible even if the users have nothing in common.
  • Executing the commands from a GUI minimizes the risk for mistakes (for example, if you forget to set the Languages-property of a mailbox before import, there is a risk that the default folders will be named in the wrong language).
  • When you work with project files, there is a smaller risk that you import data for a user twice (or forget to import data for a user).
  • There is also much easier for several administrators to hand over the migration task between each other.

PowerMigrator for PST has a already been used in a live case, to migrate mail to Microsoft Exchange, with full history maintained.

/Jesper Ståhle and Anders Hesselbom

Type safety in PowerShell

Good or bad, here are some attributes of the PowerShell type system:

Variables are declared when they are first used. Just assign a value to a variable, and the variable is created if it doesn’t exist. The variables are not type safe. Try typing $x=10 followed by $x=”Hello” and you will see that $x is happy to change type for you, without complaining. However, by specifying the type before the name of the variable, you cannot assign a value of a different type without specifying the new type.

Start by assigning an integer value to a variable, and specify the variable type in front of the variable name.

[int]$i=10

If you try to assign a different integer value to the variable $i, PowerShell will accept it.

$i=20

But if you try to assign a string value to $i, it will not work because $i only accept integer values.

$i=”Hello” #Will not work

Whenever you like, you can change the type of a variable, by specifying a new type in front of it.

[string]$i=”Hello” #Works fine – the type of $i is changed

Names are not case sensitive, so this rather poor formatted iteration will run:

FOR($x=0;$x -lt 10;$X++) { Write-Host $x }

Notice that For and FOR is the same thing, that $x and $X is the same variable, and that the curly brackets are required, even though there is only one statement that is iterated here.

Download PowerShell and activate scripting

To install Microsoft PowerShell version 1.0, you must download the correct package for your version of Windows from Microsoft Download Center. Some of the packages require that you validate your copy of Windows. 

Windows Vista

Windows XP

Windows Server 2003 

To see the complete list, search for powershell at Microsoft Download Center. Version 1.o is based on .NET Framework 2.0, so that (or a later version) must be installed. Version 2 can be downloaded here, and the current version (3.5) can be downloaded here.

You can switch to fullscreen by pressing Alt+Enter, but some of the newer graphic cards does not support the mode that it changes to. PowerShell checks this before changing the mode, so nothing bad will happen if you try this.

Allow for scripting
To check if scripting is activated in PowerShell, type:

Get-ExecutionPolicy

PowerShell should say Unrestricted, but if it says Restricted, your scripts will not be executed. To change this, type:

Set-ExecutionPolicy Unrestricted

Now you can play away with your ps1-files. 

Defining and calling functions

You can define your own functions in a PowerShell script file (PS1-file) or directly from the PowerShell console. To do this, use the keyword function, followed by the definition encapsulated in curly brackets. This code creates a function that returns a string containing the phrase “String returned from a function!”:

function myFunction { “String returned from a function!” }

To call this function, simply type myFunction and press Enter. A tip for avoiding typing long lines, you do line breaks by pressing Shift+Enter after the first line. PowerShell then enters a line editing mode. To send the text to PowerShell end exit the line editor, just pres Enter twice. PowerShell might look like this after entering and leaving the line editor:

PS H:\> function myFunction
>> {
>> “String returned from a function!”
>> }
>>

If the function you’re designing requires parameters, you can declare them in a comma separated list directly after the function name. This line defines the sum function that takes two integer parameters and returns the sum of the given values.

function sum([int]$p1, [int]$p2) { $p1+$p2 }

To call a function with parameters, enter the function name followed by the parameter values (constants or variables) separated by nothing but a whitespace.

sum 10 20

To nest the function, encapsulate it in parenthesis. This call returns the value 46:

sum (sum 10 15) 21