Friday 5 April 2013

Stopping a process with Powershell and the Out-GridView

Powershell can display a nice menu where the user can select e.g. a single or a multiple element in an arbitrary gridview, with the cmdlet Out-GridView. Let's see how this can be done to support stopping a single process of which the user chooses to stop. Of course, this is already available in Task Manager, but it is always nice to see that Powershell can give us a dedicated way of doing this also.

Here is the script for doing this, in the function Stop-SelectedProcess:

            
function Stop-SelectedProcess(){            
            
    Write-Host Select the process to stop ...            
    Start-Sleep 2            
                
    $selectedProcess = $null             
    Get-Process | Out-GridView -OutputMode Single -Outvariable selectedProcess            
                
    if ($selectedProcess -eq $null -or $selectedProcess.Count -eq 0)             
    {            
        return;            
    }             
            
    Stop-Process $selectedProcess            
            
}            
            
Stop-SelectedProcess
Make note how the Out-GridView cmdlet which we pipe the result from Get-Process to is specified to have an -OutputMode of single (i.e. choose one item at a time)and a -OutVariable also set, also note the missing $-sign after -OutVariable, this is correct. This shows how we can present the user with a nice menu to choose for while running the command. This is easier than asking the user to select a process to stop by e.g. PID or #-line number.

This is just another example of how modern as a scripting language Powershell really is.

Word of caution at the end - never stop a process you are not sure of what runs. I stopped the process smss process the other day, because I thought it was Sql Management Studio. Needless to say, I experienced my first BSOD in Windows 8 ..

Screenshot of the action:

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