Thursday 4 April 2013

Dynamic modules in Powershell as objects

This article will show how dynamic modules can act as objects for Powershell. With this technique, it is possible to create object definitions in Powershell if you want more object orientation for your scripts. Let's first look at the Manifest file for the dynamic module. The file modasobj.psd1 contains the following:

#Module manifest for module 'modasobj            
#Generated by: Tore Aurstad            
            
@{            
ModuleVersion = '1.0'            
Guid = 'C9B7488B-507C-470C-B93E-6B040A5EF2AC'            
Author='Tore Aurstad'            
Description='Demonstrates use of modules as objects'            
            
ScriptsToProcess = @('modasobj.ps1')            
            
}
The manifest file will always have the name MODULENAME.psd1, where MODULENAME is the folder name under one of your $env:psmodulepath folders. As we see, we define the Guid, Author, Description and ModuleVersion. For non-dynamic modules, we specify more properties in the hashtable of our manifest .psd1 file for our Powershell modules. An overview of the manifest properties to set is here:

How to write a module manifest
We define our module as objects definitions in the other file, modasobj.ps1
function New-Address {            
            
 New-Module -AsCustomObject -Name Address {            
    $House = $null            
    $Street = $null            
    $Town = $null            
    $County = $null            
    $Country = $null            
    $PostCode = $null             
            
    Export-ModuleMember -Variable *            
            
 }            
            
}            
            
function New-Person {            
 New-Module -AsCustomObject -Name Person {            
    $Name = $null            
    $Address = $null            
    $Occupation = $null             
    $Age = $null            
    $NiNo = $null              
            
    Export-ModuleMember -Variable *            
            
  }            
            
}
Here we see the use of New-Module cmdlet, followed by the flag -AsCustomObject and the -Name flag followed by the name of the custom object we want to create. To play around with this object, we can just create a new Person object and set its address to be an Address object. Some output of this follows.


PS C:\users> import-module modasobj -verbose -force
VERBOSE: Loading module from path 'C:\Users\Tore Aurstad\Documents\WindowsPowerShell\Modules\modasobj\modasobj.psd1'.
VERBOSE: Loading module from path 'C:\Users\Tore Aurstad\Documents\WindowsPowerShell\Modules\modasobj\modasobj.ps1'.
VERBOSE: Dot-sourcing the script file 'C:\Users\Tore
Aurstad\Documents\WindowsPowerShell\Modules\modasobj\modasobj.ps1'.
PS C:\users> $me = New-Person
PS C:\users> $me


Address    :
Age        :
Name       :
NiNo       :
Occupation :

PS C:\users> $me.Age = 34
PS C:\users> $me.Name = 'Tore Aurstad'
PS C:\users> $me.Occupation = 'System Developer'
PS C:\users> $me.Occupation = 'Systems Developer'
PS C:\users> $me.Address = 'Kyavegen 1 7045 Trondheim'
PS C:\users> $me.Address.Country = 'Norway'
Property 'Country' cannot be found on this object; make sure it exists and is settable.
At line:1 char:1
+ $me.Address.Country = 'Norway'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyAssignmentException

PS C:\users> $me.Address.County = 'Sør-Trøndelag'
Property 'County' cannot be found on this object; make sure it exists and is settable.
At line:1 char:1
+ $me.Address.County = 'Sør-Trøndelag'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyAssignmentException

PS C:\users> $address = New-Address
PS C:\users> $me.Address = $address
PS C:\users> $address.Country = 'Norway'
PS C:\users> $me


Address    : @{Country=Norway; County=; House=; PostCode=; Street=; Town=}
Age        : 34
Name       : Tore Aurstad
NiNo       :
Occupation : Systems Developer

PS C:\users> $address.County = 'Sør-Trøndelag'
PS C:\users> $address.House = '1'
PS C:\users> $address.PostCode = '7045'
PS C:\users> $address.Street = 'Kyavegen'
PS C:\users> $address.Town = 'Trondheim'
PS C:\users> $me

Address    : @{Country=Norway; County=Sør-Trøndelag; House=1; PostCode=7045; Street=Kyavegen; Town=Trondheim}
Age        : 34
Name       : Tore Aurstad
NiNo       :
Occupation : Systems Developer

PS C:\users>

PS C:\users> $me.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    PSCustomObject                           System.Object


PS C:\users> $address.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    PSCustomObject                           System.Object


PS C:\users> $me | Get-Member


   TypeName: System.Management.Automation.PSCustomObject

Name        MemberType   Definition
----        ----------   ----------
Equals      Method       bool Equals(System.Object obj)
GetHashCode Method       int GetHashCode()
GetType     Method       type GetType()
ToString    Method       string ToString()
Address     NoteProperty System.Management.Automation.PSCustomObject Address=@{Country=Norway; County=Sør-Trøndelag...
Age         NoteProperty System.Int32 Age=34
Name        NoteProperty System.String Name=Tore Aurstad
NiNo        NoteProperty  NiNo=null
Occupation  NoteProperty System.String Occupation=Systems Developer


PS C:\users>

As you can see, I had to adjust above the way I was setting $me.Address properties by having to declare a new address object $address and set its properties to see the changes reflected in the parent object $me. Both objects are of type PSCustomObject. As we can see, when we pipe our object variable to the cmdlet Get-Member, we get a nice listing of our members and derived members. This shows how custom objects can be made inline in Powershell. Of course, Powershell can create objects easily with the New-Object cmdlet and by specifying a library object either in .NET or created by you, but this shows how you don't have to recompile and create an object specification or class, you can have Powershell create for you, with dynamic modules and the -AsCustomObject and -Name flags set inside the function. In addition, you need to use the cmdlet Export-ModuleMember-Property *, such that your properties are visible for consumers of the dynamic module.

If you want to remove the module again, use:
remove-module modasobj*

Modules are a huge topic and this article shows one of their many ways of being created.

Using Powershell to generate new Guids

Guids, or Globally Unique Identifiers, are often used by developers and others to attribute a unique id to an arbitrary object. For example, those who have used WiX to create MSI-based installers, often need to create a new GUID all the time while writing the WiX code for the installer. Wouldn't it be great to use a Powershell command line to just generate new GUIDs? Here is a sample script how to do this:

            
<#
    .SYNOPSIS
        Creates a new Guid object and displays its GUI to the screen
    .DESCRIPTION
        Uses static System.Guid.NewGuid() method to create a new Guid object
    .EXAMPLE
        1. Create a new Guid is easy:
        New-Guid
#>            
function New-Guid () {            
            
 [System.Guid] $guidObject = [System.Guid]::NewGuid()            
 [Windows.Forms.Clipboard]::Clear();            
 [Windows.Forms.Clipboard]::SetText($guidObject.Guid)            
 Write-Host $guidObject.Guid            
            
}            
            
New-Guid


To call the function New-Guid just type its name. You will get new GUIDs without a hassle:


PS C:\users\Tore Aurstad> New-Guid
0d2cc38f-e6de-4049-ae6a-f168bf1ea670

PS C:\users\Tore Aurstad> New-Guid
f99044b3-a8a6-4092-a520-c58ae259a19e

PS C:\users\Tore Aurstad> New-Guid
4de11003-8bbf-4415-8fe3-e7ecf4be9ee0

PS C:\users\Tore Aurstad> New-Guid
cac473e7-1f01-4d2f-b99c-4fdb25ab9da1

PS C:\users\Tore Aurstad> 



Of course, this is very similar to creating a Console application with C#, we just call the static method NewGuid on the Guid class. In Powershell, variables can be strongly typed as shown here and to call a static method you just write [MyNamespace.MyClass]::MyStaticMethod. Note the double colon marks in the middle.

In addition to generating a new Guid, the clipboard contents is set to the Guid value, which means you can paste in the text where you want. I did not have to import any additional modules to reach the static function [Windows.Forms.Clipboard]::Clear() and [Windows.Forms.Clipboard]::SetText().

Performing backups of a database with Powershell

This article will show some Powershell script to perform a backup of a database with Powershell. Generating backups of a database is not that hard with Powershell. A backup is done by using the Server Management Objects or SMO. This is an individual download that can be downloaded for SQL Server 2008 (R2) or SQL Server 2012. I have used SQL Server 2012 Express, and this script also runs with the Express version of SQL Server 2012. I had to download additional packages for SQL from here:

Microsoft SQL Server 2012 SP1 Feature Pack

Obtain the SharedManagementObjects MSI-file and the PowershellTools MSI file, I downloaded the x64 version, but if you have x86 version of SQL Server 2012, use that instead. In addition, there are equivalent packages for Microsoft SQL Server 2008 (R2), Google is your friend here.. Here is the script to perform a backup. I have created a function or cmdlet called Backup-Database. There is also a function called PreLoad-SmoAssemblies, which I have not used, but this can be used to PreLoad the entire SMO Library if you want an example of how to do this.

            
function PreLoad-SmoAssemblies(){            
 $smoAssemblies = "Microsoft.SqlServer.Management.Common",            
"Microsoft.SqlServer.Smo",            
"Microsoft.SqlServer.Dmf ",            
"Microsoft.SqlServer.Instapi ",            
"Microsoft.SqlServer.SqlWmiManagement ",            
"Microsoft.SqlServer.ConnectionInfo ",            
"Microsoft.SqlServer.SmoExtended ",            
"Microsoft.SqlServer.SqlTDiagM ",            
"Microsoft.SqlServer.SString ",            
"Microsoft.SqlServer.Management.RegisteredServers ",            
"Microsoft.SqlServer.Management.Sdk.Sfc ",            
"Microsoft.SqlServer.SqlEnum ",            
"Microsoft.SqlServer.RegSvrEnum ",            
"Microsoft.SqlServer.WmiEnum ",            
"Microsoft.SqlServer.ServiceBrokerEnum ",            
"Microsoft.SqlServer.ConnectionInfoExtended ",            
"Microsoft.SqlServer.Management.Collector ",            
"Microsoft.SqlServer.Management.CollectorEnum",            
"Microsoft.SqlServer.Management.Dac",            
"Microsoft.SqlServer.Management.DacEnum",            
"Microsoft.SqlServer.Management.Utility";            
             
 foreach ($assembly in $smoAssemblies){            
  [void][System.Reflection.Assembly]::LoadWithPartialName($assembly);               
 }            
            
}            
            
            
function Backup-Database($dbinstance, $dbname, $saveToLocation = "C:\backups\")            
{            
             
 [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null            
 [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | Out-Null            
 [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo") | Out-Null             
 [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoEnum") | Out-Null             
            
 $dbserver = New-Object Microsoft.SqlServer.Management.Smo.Server $dbinstance            
 $bkup = New-Object Microsoft.SqlServer.Management.Smo.Backup             
 $bkup.Database = $dbname            
            
 $date = Get-Date             
 $date = $date -replace "\.", "-"             
 $date = $date -replace ":", "-"             
 $date = $date -replace " ", "-"             
            
 $file = $saveToLocation + $dbname + "_" + $date + ".bak"            
            
 $bkup.Devices.AddDevice($file, [Microsoft.SqlServer.Management.Smo.DeviceType]::File)             
 $bkup.Action = [Microsoft.SqlServer.Management.Smo.BackupActionType]::Database             
            
 $bkup.SqlBackup($dbinstance)            
            
 Write-Host "Backup of database $database performed at $(Get-Date) to file location $saveToLocation"            
            
 trap [Exception]             
 {            
  Write-Host $_.Exception.Message            
  break            
 }            
            
}            
            
$dbinstanceToUse = $env:COMPUTERNAME + "\SQLEXPRESS"            
$dbnameToUse = "TestDatabase"             
            
Backup-Database $dbinstanceToUse $dbnameToUse             
The function or cmdlet Backup-Database takes three parameters. The $dbinstance is the computer name - db instance name to use for the $dbserver inside the function. The $dbname is the name of the database, while $saveToLocation is the location where to save the .bak backup file. Each .bak file will get a name of $dbname concatenated with a date stamp with the .bak extension in the end of the file name. The file location can be specified, but will default to c:\backups. Obviously, you want to either specify this or make sure that the location c:\backup exists first. The script can be adjusted by using Test-Path to make sure that the folder exists first.

This shows how Powershell can be used for a wide variety of tasks, such as performing a backup of a SQL server database.

Wednesday 3 April 2013

Eventlog and Powershell

Powershell can use the EventLog from the Powershell command line easily. This article will quickly display some Powershell script for handling the Eventlog:
new-eventlog -logname Application -Source MyCoolPowershellLog            
write-eventlog -Source MyCoolPowershellLog -EventId 0001 -Message "This is an
event registered by Powershell" -EntryType Information            
write-eventlog -LogName Application -Source MyCoolPowershellLog -EventId 0001 -Message "This is an event registered by Powershell" -EntryType Information            
get-eventlog -logname Application -Newest 10
To create a new source, we use the new-eventlog cmdlet and specify the logname, set here to Application. To create a new event, we use write-eventlog cmdlet. Here we supply the LogName, Source, EventId, Message and EntryType. EntryType can be Information, Warning and Error. To get the content in the eventlog, we can use the get-eventlog cmdlet.

Finally, to remove the Eventlog Source, use:

remove-eventlog -source MyCoolPowershellLog

Make note, this will delete the eventlog source, but not its already recorded events. Now, new events can be written to this eventlog source. Actually the old events of the eventlog source still exists on the system, as you can't remove events themselves from an eventlog source, as is the convention.

Tuesday 2 April 2013

Using Powershell to perform automatic Hg Bisect

The process of bisection in the source control system Mercurial or Hg is done with the command Hg Bisect. The Hg Bisect command is usually run manually and consists of manual steps done by the user where the developer running the hg bisect command looks for a certain condition should hold true and mark each revision as either good or bad. This is done in a binary search result manner, which quickly narrows down the number of revisions to look at by half for each iteration. The goal is to find the first revision containing a bad feature. An automatic function for finding such bad features will now be presented. Here is the Powershell cmdlet or function followed by an example of a call to this function:

function Get-HgChangeSet(            
){            
    param(            
    [Parameter(Mandatory=$true)]            
    [scriptblock]             
    $test,             
            
    [Parameter()]            
    $good = 0,            
            
    [Parameter()]            
    $bad = 'tip'             
    )            
            
    hg bisect --reset;            
    hg bisect --bad $bad;             
    (hg bisect --good $good) | out-null;             
            
    while ($output -notmatch 'The first bad revision is'){            
        $result = & $test;             
            
        if ($result){            
            $output = (hg bisect --good ) | out-string;             
        }            
        else {            
            $output = (hg bisect --bad) | out-string;             
        }            
    }            
            
    $output;             
}            
            
Push-Location 'C:\toaurs-he\demorepo\'             
Get-HgChangeSet { !(Test-Path 'test.txt') -or (Get-Content test.txt) -notmatch 'ultrabad' }            
Pop-Location


In this example, a simple demo repository has a file called test.txt. I want to find the first revision where the text ultrabad was inserted. The truth condition then, is that either the file does not exist (yet) in a revision, or that the file exists and does not match ultrabad. This is a simple example, but it shows how one can search for a given text or source code by specifying this in the script block passed to the function or cmdlet Get-HgChangeSet. When the script is run, it finds the first occurence of the text ultrabad (which is bad) at revision number 8.

PS C:\toaurs-he\demorepo[ default ]> 
Hit Line breakpoint on 'C:\Users\Tore Aurstad\Documents\WindowsPowerShell\Scripts\Hg\BisectTool.ps1:22'
PS C:\toaurs-he\demorepo[ default ]> 
The first bad revision is:
changeset:   8:25be1d61e90d
user:        Tore Aurstad 
date:        Tue Apr 02 22:09:15 2013 +0200
summary:     foo 4
So there you have it, an automatic way via a Powershell script to find an introduction of a bad feature in a Hg repository with the aid of a Powershell function or cmdlet. To use this script, it is important to understand that the passed in first argument is a truth condition. It will usually always be necessary to accept if the file to test does not exist yet combined with and -or condition and then specify -notmatch and the text or source code which is not desired. This will usually be more precise than running hg bisect manually, which is kind of tedious still.

Also note that the second and third parameter is set to $good equals 0 and $bad equals 'tip'. In Mercurial or Hg, 'tip' is the newest revision. Usually, for a repository with many revisions, it will be quicker if the values for $good and $bad is specified in a well-known range, say revision 5000 to 5500 or what have you.. This is just another example of how scripting can lighten our daily workload as developers.

Using Psake to build Visual Studio solutions

Psake is a build automation tool that can be used as an alternative to the ubiqutous MsBuild XML files for .NET developers. Psake is a module for Powershell and this means your build scripts will have easy access to other resources such as remote Web Servers and file systems or other required resources in the build process. In addition, building software is primarily a procedural process and using a script with the aid of Psake makes more sense than using MSBuild XML files. It is also quicker to avoid creating MSBuild tasks and so on. Let't take a look at a sample Psake build script:
#tasks.ps1            
            
properties {            
 $config = 'debug'; #debug or release             
}            
            
task -name PackageZip -depends Build -description "proceduces a zip archive of the build output" -action {            
    import-module pscx             
    write -host "Packaging files"            
    write-host $config             
    Push-Location 'C:\Users\Tore Aurstad\Documents\visual studio 2012\Projects\TestLDAP\TestLDAP\bin'            
    dir $config\ | write-zip -output $pwd\$config\TestLDAP.zip            
    Pop-Location            
}            
            
task -name ValidateConfig -action {            
 assert ( 'debug', 'release' -contains $config) `
 "Invalid config: $config; valid values are debug and release";             
}            
            
task -name Build -depends ValidateConfig -description "builds outdated source files" -action {            
    write-host 'The build task is now running';            
    exec {            
        msbuild 'C:\Users\Tore Aurstad\Documents\visual studio 2012\Projects\TestLDAP\TestLDAP.sln' /p:Configuration=$config            
    }            
}            
            
task -name Clean -description "deletes all build artifacts" -action {            
    write-host 'The clean task is now running';             
     exec {            
        msbuild 'C:\Users\Tore Aurstad\Documents\visual studio 2012\Projects\TestLDAP\TestLDAP.sln' /t:Clean /p:Configuration=$config             
    }            
}            
            
task -name Rebuild -depends Clean,Build -action {            
    write-host 'The rebuild task is now running';             
}            
            
task default -depends Build;


The following command then will invoke one of the build targets in the Psake build scripts:

PS C:\users\Tore Aurstad\Documents\WindowsPowerShell\scripts> invoke-psake -buildfile .\script1.ps1 -task PackageZip Before running the script1.ps script file, which I have put in the Scripts folder of the parent folder of the $env:psmodulepath. In addition, psake had to be installed. To install psake, download the .zip file of this Powershell module from the following url:

Psake Github

Save the .zip file to your hard disk, unblock the zip file using file properties and click Anvanced button. Unzip the file contents and move the files into the $env:psmodulespath folder, in a subfolder called psake.

When psake is ready on your system, check that you have the correct execution policy. Run if necessary: Set-ExecutionPolicy RemoteSigned in Powershell.

The psake script contains of multiple task declarations. The task default is obligatory. The other tasks has action blocks, and some of these calls msbuild inside an exec block.

The module pscx is also used to zip the output of running msbuild. The module is available here:
Pscx module. This module is the Powershell Community Extensions powershell module. The module is a central extension module of Powershell. By piping the output of the dir command against the output files and using the cmdlet write-zip and the argument -output following by the file name of the zip file to create, the output is zipped together.

Also make note that tasks can depend upon oter tasks with their -depends flag. To toggle between the debug or release configuration, it is possible to set this by using the -properties flag on the invoke-psake command. To build in release, simply specify this as in the following example:

PS C:\users\Tore Aurstad\Documents\WindowsPowerShell\scripts> invoke-psake -buildfile .\script1.ps1 -task Rebuild -properties @{ 'config' = 'release' } By setting -properties flag and passing in a hashtable where the key 'config' is set to the value 'release', it is possible to build in release mode instead of debug mode. There is also a ValidateConfig task that will check that the provided value is either 'debug' or 'release' or some other value. The assert expression will check that the specified configuration is one of the two valid values. There is a correspondence between the property in the -properties flag and the property declared in the psake script.

Psake can be integrated into TeamCity and you can transform the functionality of the MSBuild Xml file (usually a .proj file) into a psake script. Once this is done, it is much more flexible to make changes since the build script now is inside a Powershell script. Forget creating MSBuild tasks which are compiled, this will instead be other Powershell scripts.

Here is a tutorial on how to integrate psake in Team City:

Psake and Team City

Sunday 31 March 2013

Searching for text in files with Powershell

This article will present a way of searching for text in files on your hard disk using Powershell. There are of course many ways of achieving this, such as findstr command. I call the function I present here as grep, but this is in no way anything similar to the sophisticated grep tool many users from Unix-based operative systems are familiar with. The output this command gives gives a nice summary of line number and file
function grep($searchPattern, $fileMatch = '*.*', [bool] $ignoreCase = $true){            
             
 if ($ignoreCase){            
  Get-ChildItem -Recurse -Filter $fileMatch | Select-String -Pattern $searchPattern |            
  Format-Table -GroupBy Path -AutoSize            
 }            
 else {            
  Get-ChildItem -Recurse -Filter $fileMatch |             
  Select-String -Pattern $searchPattern -CaseSensitive |            
  Format-Table -GroupBy Path -AutoSize            
 }            
}            
            
grep AsFullName *.cs $true            


The cmdlet above is called grep, but this does not apply to the verb-noun standard of Powershell. A better name could be Search-Files or something similar. The function uses the Get-ChildItem cmdlet with the recurse option to search all files (and folders) recursively from the current working directory and all its subfolders. This is then piped to Select-String and the flag -CaseSensitive is set if $ignorecase is set to $false. As you can see, the default value of the second and third parameter to the function /cmdlet is '*.*' for $fileMatch and $true for $ignoreCase. A function call is done in the code shown above as an example. Make note that only the first parameter is required, the search string. If a case sensitive search is desired, one must specify all three parameters. If it is desired to search through all files, use '*.*'. In my example, I am looking through some source code, and I am only interested in looking at the files with the extension '.cs' (C# source code files).

It is possible to compact the function or cmdlet above by making use of emulating the ternary operator, but the script above is easy should be easy to debug. If $ignoreCase is set to $false, the -CaseSensitive flag is used in the Search-String cmdlet in the script above.

The output of the command is shown below, when the working directory is set to the source code folder where I have cloned the source code of ShellStudio:

PS C:\toaurs-he\StudioShell\studioshell[ default ]> grep AsFullName *.cs


   Path: C:\toaurs-he\StudioShell\studioshell\src\CodeOwls.StudioShell\CodeOwls.StudioShell.Paths\Items\CodeModel\ShellCodeTypeReference.cs

IgnoreCase LineNumber Line                                            Filename                  Path                                                                              
---------- ---------- ----                                            --------                  ----                                                                              
      True         54         public string AsFullName                ShellCodeTypeReference.cs C:\toaurs-he\StudioShell\studioshell\src\CodeOwls.StudioShell\CodeOwls.StudioSh...
      True         56             get { return _typeRef.AsFullName; } ShellCodeTypeReference.cs C:\toaurs-he\StudioShell\studioshell\src\CodeOwls.StudioShell\CodeOwls.StudioSh...

Using Studioshell to prefix booleans with Is

An often used convention used in coding is to prefix boolean properties that are public with the prefix Is. In this article, an automatic refactoring technique will be explained using Powershell. Alternatives could be using Resharper or Roslyn. Since Powershell will tackle this on a file level, it will execute very fast. Using Powershell alone will not be sufficient, since Powershell does not have the needed code analysis capabilities. To tackle this, we will useStudioshell and execute the script presented in this article.
To download Studioshell, visit the following url:
Studioshell codeplex page

As an alternative, download and install StudioShell via NuGet. Open up a new solution in Visual Studio, then choose the menu option Tools, Library Package Manager and Package manager console. Choose your main project or what's best suited and run the command:
Install-Package StudioShell.Beta

When StudioShell is installed, check that the Execution Policy is remote signed. Start Visual Studio as an administrator and run the following cmdlet: Set-ExecutionPolicy RemoteSigned . StudioShell has its own profile file. Let's first create the profile file, if necessary. Run the following cmdlet: New-Item -ItemType File $profile Add the following function to the $profile file, by running the following cmdlet to open up the $profile file in Notepad: Invoke-Item $profile The automatic refactoring function in Powershell with the help of StudioShell then looks like this:

function PrefixWithIs-Booleans(){            
 Set-Location dte:\solution\codemodel            
        dir -recurse | where { $_ -match 'property' -and $_.name -notMatch '^Is' -and $_.access -match 'public' -and             
        $_.type.asfullname -match 'bool' } | foreach { $newname = "Is" + $_.name; $_.renamesymbol($newname); }            
            
}
Of course, this function could be put in a .ps1 or .psm1 file instead of residing in your StudioShell profile file. By putting the function or cmdlet into the $profile file, it will always be available in StudioShell. As you can also see, the cmdlet is named with verb-noun, as is the convention in Powershell. To run this cmdlet, just type: PrefixWithIs-Booleans This cmdlet will automatically rename all public properties that return a boolean and that has not have the prefix Is, and rename this public property to have the prefix Is. This will result that all public properties start with Is. The cmdlet PrefixWithIs-Booleans starts with running the dir -recurse command to recursively look at all files (and folders) in subdirectories. But first the location is changed to dte:\solution\codemodel. Studioshell has a folder structure which is used for the analysis of code of the currently loaded solution. By then looking at all files (and folders) in the folder dte:\solution\codemodel, effectively one is looking at the entire Visual Studio solution. The property of the items one is looking at is CodeOwls.StudioShell.Paths.Items.CodeModel.ShellCodeProperty2. The command dir -recurse is piped to the cmdlet where and the long where condition effectively looks for boolean properties that are public and does not have a name starting with Is. The result set is then furter piped to foreach which will iterate on the current object in Powershell, $_ and then call the renamesymbol method of the current object. The new name is then set to Is + name member of current object. This shows how Studioshell can refactor a Visual Studio solution using the dte: folder structure of Studioshell and then to code manipulation on the Visual Studio. It is important to be careful when using Studioshell, I would suggest using a versioning system such as Mercurial. Studioshell can also automate a multitude of features in Visual Studio besides code manipulation and code analysis. For example, it is possible to save window layout and load up a window layout with a single command from the shell command line of Studioshell inside Visual Studio. It is also possible to toggle on and off all breakpoints and so on. If you find yourself doing repetitive tasks in Visual Studio or changing the code in a repetitive manner, consider using StudioShell for automating these tasks.

Saturday 30 March 2013

Creating a Mercurial-aware Powershell command line

This article will describe how we can create a Mercurial-aware Powershell command line. Mercurial is a (distributed) source control. It supports branch per feature and multiple other nice features that gives powerful control of the source code. To get Mercurial, check out the following url: Mercurial The Mercurial-aware Powershell command line will detect when the user enters a Mercurial repository folder on disk. This will be done via the hg branch command, which will return null if the user is not in a Mercurial folder and the name of the branch if the user is inside a Mercurial repository. Let's look at the needed code first, I put this code in my $profile file, use the cmdlet inside Powershell to open the $profile file: Invoke-Item $profile This will edit the profile file of your Powershell by launching Notepad. The $profile file is not perhaps created yet. If that is the case, enter the following command: new-item -ItemType file -path $profile Now retry the command Invoke-Item $profile if this command failed. If you just type: $profile at the Powershell prompt, you will get the file location of the profile file. Make note that Powershell ISE and Powershell prompt has different profile files.. Before I can show you the script, I must get the script transformed into readable colored HTML right? I type Import-Module PowershellPack, now I can use the nice cmdlet Copy-ColoredHTML. This copies the script as colored HTML into the clipboard. I can then paste the
function get-hgStatus(            
    $status = @('M','A','R','C','!','?','I')            
){            
    hg status --all |            
        where { $_ -match "^\s*[$Status]" } |            
        foreach { $_ -replace "\s+", ',' } |            
        ConvertFrom-Csv -Header Status, Path             
            
}            
            
function prompt {            
             
 $branch = (hg branch);            
 $status = get-hgStatus | Group-Object Status;            
            
 $modified = $status | where { $_.name -eq 'M' } | select -expand count;             
 $added = $status | where { $_.name -eq 'A' } | select -expand count;             
 $removed = $status | where { $_.name -eq 'R' } | select -expand count;             
 $untracked = $status | where { $_.name -eq '?' } | select -expand count;             
 $missing = $status | where { $_.name -eq '!' } | select -expand count;             
            
 Write-Host "PS $pwd" -NoNewline            
            
 if ($branch){            
              
  write-host "[" -NoNewline            
  write-host " $branch " -ForegroundColor White -NoNewline            
              
  if ($added){            
    write-host " " -NoNewline            
    write-host "+$added" -ForegroundColor green -NoNewline;            
  }            
            
  if ($modified){            
    write-host " " -NoNewline            
    write-host $modified -ForegroundColor yellow -NoNewline;            
  }            
            
  if ($removed){            
    write-host " " -NoNewline            
    write-host "-$removed" -ForegroundColor magenta -NoNewline;            
  }            
            
  if ($missing){            
    write-host " " -NoNewline            
    write-host "!$missing" -ForegroundColor red -NoNewline;            
  }            
            
  if ($untracked){            
    write-host " " -NoNewline            
    write-host "?$untracked" -ForegroundColor gray -NoNewline;            
  }               
            
  write-host "]" -NoNewline;            
            
 }            
            
 "> "            
            
}            
Note the use of a default value in the passed in $status variable, which is default set to an array of all the possible hg status flags. The hg-GetStatus function can be called individually like hg-GetStatus A to show all the added files in the repo. The script above uses the hg status command to get the status of the current hg repository in the folder. If the current folder is not a hg repository, a default prompt is shown instead. The output of the command hg status is converted into a structured object and then grouped by status using the Group-Object cmdlet. A pipeline is used to prepare the output of the hg status before it is transformed into the structured object. The count of each group is retrieved with the Select cmdlet, and using the -extract flag. The group counts are then shown to the user in the prompt and formatted with color. Make note of the use of -NoNewLine and -ForegroundColor. In addition, the Powershell function prompt will control how your prompt in the shell will look like, i.e. the command line. I put this prompt in the $profile file such that this is inited each time.

This is just an introduction to customizing the Powershell command line to a more suited hg aware prompt for developers using hg. There is actually already a better package available on the Internet for displaying the state of the hg repository in the folder displayed in Powershell, which is called hg posh. Check out hg posh on the following url:
hg posh


However, although hg posh is more correct, I like the look of this command prompt better ... For many hg users, this will suffice.. And here is our nice new Mercurial aware command line:

Friday 29 March 2013

Hashtables in Powershell

Hashtables are good for creating dictionary-like data structures in Powershell, for look-ups and related functionality. The following powershell script code shows how to create a Hashtable in Powershell and to use and modify this datastructure:
$countries = @{            
    "Norway" = "Oslo";            
    "Denmark" = "Copenhagen";            
    "Sweden" = "Stockholm";            
    "Germany" = "Berlin";            
    "Italy" = "Rome";            
    "Burkina Faso" = "Ougadougou";            
};             
            
            
$countries.'Burkina Faso'            
$countries.ContainsKey('Norway')            
$countries.ContainsValue('Ougadougou')             
$countries.ContainsValue('London')            
$countries['Sweden']             
$countries.Add('France', 'Paris')             
$countries.France             
            
$countries.Remove('Burkina Faso')             
            
$countries.ContainsKey('Burkina Faso')
The code above creates a hashtable using the @{ and } literals, where each key and value is defined by key = value followed with a semicolon, note that this is optional and can be omitted. Hashtables are very user-friendly in Powershell. One can address a value in the hashtable by passing in the key in square brackets, like an index. It is also possible to perform manipulation of the hashtable, using Remove and Add. For the Add method, one supplies the key and value pair to add. For the Remove method, one supplies to the key to look for and then remove (this will of course also remove the value of the key-value pair).

It is also possible to query the hashtable using ContainsKey and ContainsValue methods, looking for keys or values. Note also that members of the hash table is available and shown in Intellisense using the Powershell ISE (Integrated Shell Environment). It is possible to say $countries.France, or $countries.'Burkina Faso'. The last hash table key address is encapsulated in quotes, since there is a space in the key. When calling GetType() on the hashtable instance $countries, the name Hashtable is shown.

To list up the keys and the values of a hashtable, use the Keys or Values member of the hashtable. Example:
$countries.Keys            
$countries.Values

Keyboard input in Powershell

Keyboard input in Powershell

Asking users for input in Powershell is very straight-forward. Use the Read-Host cmdlet in Powershell and add a string value to the -Prompt switch of the cmdlet to specify which text to display to the user. Assign the result from Read-Host to a Powershell variable, e.g. $myvariable. This variable can then be treated logically and control the further program execution and logical flow of the program.

The following code shows how this can be done:

            
function Ask-FavoriteColor ([int] $personsToAsk){            
<#
    .SYNOPSIS
    Ask about the favorite color
    .DESCRIPTION
    The favorite color was asked in the movie "Holy Grail"
    .PARAMETER personsToAsk
    The number of persons to ask
#>            
 foreach ($i in 1..$personsToAsk){            
            
  [string] $color = Read-Host -Prompt "What is your favorite color?"            
            
  if ($color.ToLower() -ne "blue"){            
     Write-Host "You didn't say blue!"             
  }            
  else {            
     Write-Host "Good choice!"             
  }            
 }            
            
}            
            
Ask-FavoriteColor 2


If you see the text at the top of the function, you will see how one can document the function using meta keywords such as .SYNOPSIS and .DESCRIPTION. When using the Powershell cmdlet Get-Help, e.g. Get-Help Ask-FavoriteColor -detailed, one will see the (detailed) documentation in the Powershell help page. This is rather equivalent to the obiqutous man command seen in Unix-based systems.

When creating Powershell functions, your functions should be documented using this technique. There are lots of other meta keywords that can be used. See this overview for meta keywords for documentation.

PS C:\Users\Tore Aurstad\Documents\Powershell Scripts\files> C:\Users\Tore Aurstad\Documents\Powershell Scripts\Input\KeyboardInput.ps1
What is your favorite color?: red
You didn't say blue!
What is your favorite color?: blue
Good choice!

'
PS C:\Users\Tore Aurstad\Documents\Powershell Scripts\files> Get-Help Ask-FavoriteColor -Detailed NAME Ask-FavoriteColor SYNOPSIS Ask about the favorite color SYNTAX Ask-FavoriteColor [[-personsToAsk] ] [] DESCRIPTION The favorite color was asked in the movie "Holy Grail" PARAMETERS -personsToAsk The number of persons to ask This cmdlet supports the common parameters: Verbose, Debug, ErrorAction, ErrorVariable, WarningAction, WarningVariable, OutBuffer and OutVariable. For more information, see about_CommonParameters (http://go.microsoft.com/fwlink/?LinkID=113216). REMARKS To see the examples, type: "get-help Ask-FavoriteColor -examples". For more information, type: "get-help Ask-FavoriteColor -detailed". For technical information, type: "get-help Ask-FavoriteColor -full".

Exception handling in Powershell scripts

Exception handling in Powershell

Powershell is capable of handling exceptions in your Powershell scripts. Instead of the familiar try-catch construct, you use the trap keyword. The trap keyword followed by a block clause for handling the exception can be anywhere inside a Powershell function, at the top, middle or bottom of the method. I would suggest keeping the trap keywords at the bottom for readability. After all, your function's code is what is most important and exception handling is secondary. Still, the scripts should contain good exception handling for expected errors. In addition, a universal exception handler can be achieved by trapping the [System.Exception] exception, i.e. any exception. It is though better to trap the expected exceptions and unexpected exceptions should be thrown. 
#clear screen first using Clear-Host             
Clear-Host             
            
function Divide([int]$a, [int]$b){            
            
 $answer = $a / $b;            
 Write-Host $answer             
            
 trap [System.DivideByZeroException] {            
    Write-Host Attempted to divide by zero!            
    continue            
 }            
 trap [System.Exception] {            
    Write-Host Unexpected Exception. Breaking out of function.            
    break            
 }            
            
}            
            
Divide 15 3            
Divide 75 15            
Divide 95 5            
Divide 111 0            
Divide 64 8            
Divide 4 2.3             
            



As seen in the Powerscript code above, the trap keyword is followed by the error handling code. Usually, doing a Write-Host or logging the error is what will be done here (Write-Host corresponds to Console.WriteLine) in .NET based programming languages.

It is possible to have multiple trap statements with individual Exception types. In this example, the [System.DivideByZeroException] is handled. The keyword continue basically means that execution is permitted to continue. In the other trap statement, the keyword break is used. This basically is the same as a throw statement in a corresponding try-catch clause, where program execution is halted in the function. Judge which exceptions should be allowed to continue, and which exceptions should be allowed to break.

This is just another example of how powerful Powerscript is when it comes to a shell script. Of course, shell scripting languages such as Perl sports most of the functionality. The ability of Powershell to make use of .NET (after all Powershell is built upon .NET), means many .NET developers will quickly find new uses of Powershell by making use of previous knowledge and experience in .NET.

To sum up, your Powershell scripts should have the necessary trap statements for error-handling. As a sidenote, I do not like the keyword trap, they should have called it catch or something more trustworthy ..

Thursday 28 March 2013

Using Powershell to download multiple files

Powershell


Powershell is a shell scripting language with command line access, based on .NET, which  gives
the user and the developer access to an abundance of system resources, plus intra- and internetworked resources. In this article, an example of how Powershell can be used to download multiple files from the internet, and save these files to a local file folder, will be given.

Powershell is as previously mentioned based upon .NET. This gives Powershell many capabilities as a command line shell and scripting language. Syntaxwise, Powershell in many respects are similar to Perl or PHP, but there are also simliaries to other .NET Languages. At the same time, this is a command line shell script. It's role is to inherit the role that the Command Line Prompt (CMD.exe) and MS-DOS previously covered. Instead of the .BAT files of CMD and  MS-DOS, scripts are written in Powershell scripts, with the extension .PS1. There are more advanced topics to cover, such as modules of Powershell, but this article will cover some basic use of Powershell.

I have used the Windows Powershell ISE, which is the Integrated Script Environment.
The term ISE is similar to IDE, which stands for Integrated Development Environment. Powershell ISE is included in Windows 8, which I have used. Windows 7 users can download the Windows Management Framework 3.0 package, which is available at the following URL:

http://www.microsoft.com/en-us/download/details.aspx?id=34595


The above package is available also for Windows 2008 Server R2 and Windows 2012 Server.

Downloading files with Powershell

Let's first review the script which downloads some files (in my example I create an Object array of Url addresses which points to Flickr thumbnail images of mine).

            
$flickrImages = 'http://farm9.static.flickr.com/8370/8595533065_4f19f05869_m.jpg',             
'http://farm9.static.flickr.com/8239/8566909448_cac6a5ea75_m.jpg',             
'http://farm9.static.flickr.com/8375/8566909032_70866e8ce7_m.jpg',             
'http://farm9.static.flickr.com/8520/8566908388_2d0bcdc572_m.jpg',             
'http://farm9.static.flickr.com/8049/8131277333_83586d9afc_m.jpg',             
'http://farm9.static.flickr.com/8291/7605276718_a7e8c2d7d8_m.jpg',             
'http://farm6.static.flickr.com/5321/7407130682_c4c26ca2d9_m.jpg',             
'http://farm8.static.flickr.com/7089/7379569808_8e0311918c_m.jpg',             
'http://farm8.static.flickr.com/7088/7378798094_ac05bedf72_m.jpg',             
'http://farm8.static.flickr.com/7245/7217153808_f4e5125b4e_m.jpg',             
'http://farm8.static.flickr.com/7243/7217105052_6b1fc818f8_m.jpg',             
'http://farm9.static.flickr.com/8143/7191404308_47bb667be6_m.jpg',             
'http://farm8.static.flickr.com/7089/7149219081_bfe587bd34_m.jpg',             
'http://farm8.static.flickr.com/7260/7145533071_c7241d0064_m.jpg',             
'http://farm8.static.flickr.com/7048/6999442724_e399e63e68_m.jpg',             
'http://farm9.static.flickr.com/8158/6986866246_d04ec09342_m.jpg',             
'http://farm8.static.flickr.com/7124/7057325243_db81f4c65a_m.jpg',             
'http://farm8.static.flickr.com/7089/6911179760_24654b32fd_m.jpg',             
'http://farm8.static.flickr.com/7268/6910639934_31cd36a854_m.jpg',             
'http://farm8.static.flickr.com/7274/7052136425_6be954f436_m.jpg',             
'http://farm8.static.flickr.com/7037/7052113599_2a249aa763_m.jpg',             
'http://farm8.static.flickr.com/7072/6906010348_1fd6513b31_m.jpg',             
'http://farm8.static.flickr.com/7089/6902820096_95a7ec11c4_m.jpg',             
'http://farm8.static.flickr.com/7280/7048911257_89ae08a75e_m.jpg',             
'http://farm6.static.flickr.com/5467/7048911105_7370eff5ef_m.jpg',            
'http://farm6.static.flickr.com/5031/6902819694_763fc65fe0_m.jpg',             
'http://farm6.static.flickr.com/5234/6902819562_0f78bc56f4_m.jpg',             
'http://farm8.static.flickr.com/7279/7048910545_f02faeda37_m.jpg',             
'http://farm8.static.flickr.com/7080/7047789289_c93ff1deac_m.jpg',             
'http://farm8.static.flickr.com/7220/7047688059_216d67e9d3_m.jpg',             
'http://farm8.static.flickr.com/7092/6901520442_637c138c1f_m.jpg'            
            
$targetDir = 'C:\users\Tore Aurstad\Documents\Powershell Scripts\WebClient\'            
            
            
function DownloadFile([Object[]] $sourceFiles,[string]$targetDirectory) {            
 $wc = New-Object System.Net.WebClient            
             
 foreach ($sourceFile in $sourceFiles){            
  $sourceFileName = $sourceFile.SubString($sourceFile.LastIndexOf('/')+1)            
  $targetFileName = $targetDirectory + $sourceFileName            
  $wc.DownloadFile($sourceFile, $targetFileName)            
  Write-Host "Downloaded $sourceFile to file location $targetFileName"             
 }            
            
}            
            
DownloadFile $flickrImages $targetDir            

Many .NET developers are unfamiliar with Powershell scripting language syntax. Variables are declared by prefixing the variable name with the $-sign. I declare an Object Array, which is basically a comma separated list. This syntax will be familiar to Perl Developers. Also note the absence of semi-colons. Semi-colons are not obligatory in Powershell, and these are therefore omitted.

Further on, I declare a variable for where to put the downloaded files. If you want to test out this script yourself, you have to change this path, obviously.
Next on, I declare a function in Powershell for downloading the files. This function takes in an Object array and a string for the target Directory or folder.

The function is called without using commas or parentheses. In Powershell every function argument is passed in using spaces. This is where the Powershell syntax feels a bit different to other Microsoft Languages. If you use commas when calling the function in this example, the first argument will receive an Object Array, while the second argument will be empty. Be aware of this Powershell gotcha - use spaces when calling a function with multiple arguments.

Let's investigate the function a bit closer. As you can see, although Powershell allows mutable types (which means that a variable containing for example a string can be redefined to an integer), prefixing the arguments with square brackets and a type, such as [Object[]] or [string], makes your Powershell scripts more type-safe. Powershell obviously in many cases feels like Javascript for example, where also a variable can be changed into another type (redefined). If you want to have more type safety, prefix your function arguments with the strongly type you expect being passed into the Powershell function. The variable $wc is instantiated into a new System.Net.WebClient instance, using the New-Object cmdlet (Command let) in Powershell. To perform the download of each file in the passed in Object Array, I use a foreach loop.

This is where Powershell shows itself as a convenient scripting language. Iterating through a collection using foreach loop makes coding much easier, note though that Perl already implemented this functionality some years ago. Inside the foreach loop, the call to the function or method $wc.DownloadFile downloads the file from the Internet using the instantiated WebClient. I am not sure if .BAT files could achieve this, but this shows how much functionality is available to Powershell users and Developers. Powershell is well suited for system maintenance and administration, plus actually are larger part of target uses than one might think of a shell script language and command line tool.

The fact that much of .NET is available means that .NET Developers in some cases must rethink their use of the relationship between compiled programs and scripts, now that Powershell is so available. The added convenience and flexibility of Powershell, plus functionality makes Powershell a contender among the more mature .NET Programming Languages such as VB and C#. If you implemement something in a Programming language, think of doing the same in a script. Sometimes going for a script based solution will be better, more flexible and optimal.

For developers using .NET, the use of SubString and LastIndexOf shows that many .NET methods and types are available for us in Powershell.

If you wonder how I formatted the Powershell code above, I downloaded the PowerShellPack utility from here:

Powershell pack

After you have downloaded PowershellPack and installed it, follow the following guide:

Copy selected text in Powershell ISE to colored Html


Click the thumbnail below to see the script running inside Windows Powershell ISE:




Windows Powershell ISE has an editor and a command line below, where Powershell scripts can be executed and Powershell itself can be used. To start the PowerShell script, I type .\WebClient.ps1, since I saved the script above in a file called WebClient.ps1.

Users of BASH and other shell scripting Languages will feel familiar using Powershell, as multiple commands are linked to Unix familiar commands, such as DIR in MS-DOS and CMD is aliased to the command ls. More commands can be aliased, such that Unix Developers can manage part of Windows Clients and servers and still have that familiar Unix syntax feel of it ... This concludes our introductory tour of Powershell. I would like to say happy coding, but it is perhaps more correct to say happy (Powershell) scripting?