## 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


$_.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. ## Friday, 29 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+", ',' } |

}

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:

### 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?"

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 .. ### 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/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