Search

my categories

Blogroll

quick and dirty new custom object

January 24th, 2010 by Karl

I’ve been looking through a bunch of my old scripts (pre 2007) and found an interesting new-pscustomobject. I wouldn’t recommend you use this since now there are better ways in V2, and if you wanted to do anything more its better to use or build a more elegant custom object DSL/DSV that takes into account many aspects. This script was originally a one liner but i split it up to make it more pretty for the blog.

function new-pscustomobject ([string[]] $names , [object[]] $values )
{$obj = 1| select-object $names;
0..($names.length-1) | % { $obj.$($names[$_]) = $values[$_] };$obj
}

and you could use it like

new-pscustomobject -names name, age, height -values "karl", 29, 195

Whats interesting here are a few things.. one using select-object as a quick and dirty way of creating a stub object with properties without values.. the 1 | pipeing is just to get it to run once and create one object… it really could be anything. Another thing is using the 0..(whatever) to create a collection, and then use foreach to iterate over that. Its very “PowerShelleze” but a fair bit slower than a foreach ($x in $y) or a for loop. I think the real “dynamic language” feature this shows up, is address properties of an object dynamically with $obj.$(expression) where expression calculates the name of the property. That feature of powershell comes in handy so often for me, and cuts down many a 200 line C# solution into a one liner.

Posted in Powershell | 1 Comment »

Would the real PowerShell V2 stand up?

January 21st, 2010 by Karl

There is alot of confusion about which PowerShell V2 to download. The problem is if you search for Download PowerShell V2, the most prominent hits are PowerShell V2 CTP – basically an Old Beta. Microsoft has to keep that up because there are production things that actually use that (like outlook@edu) . The best URL path to follow is to go to Microsofts official PowerShell Page at http://www.microsoft.com/powershell and follow the download page links from there.
if you want to go directly to the V2 Download page now though here is a direct link http://support.microsoft.com/kb/968929

One of the reasons why it doesn’t show up is the install isn’t just PowerShell but packaged with WinRM (and optionally Bits 4.0) as something called “Windows Management Framework” . This is good to know and remember since that is what will show up in your add/remove programs if you ever need to remove it.

Posted in Powershell | 1 Comment »

Quick and Dirty C# Expressions from within Powershell.

January 16th, 2010 by Karl

Have you ever just wanted to run a line or two of C# from within PowerShell and consume the resulting objects from PowerShell? Before V2 you had to do some codedom yourself Plus write a full dotnet class yourself. With V2 you can just do add-type but still you have to write a full class just to run an expression.

Anyway how about a year ago after getting fed up with doing that, and also after seeing Mono’s C# commandline interface i thought lets do something quick and dirty that could do this..

with the script that will follow you can do stuff like (c being an alias for the function that compiles and runs a C# expression

(c DateTime.Now).adddays(5)
(c "new{a=1,b=2,c=3}").b
c 'from x in Directory.GetFiles(@"f:\downloads") where x.Contains("win") select x'

an interesting thing i found out, was that with the C# compiler in memory i can’t create more than one anonymous type (2nd example above) with the same signature (i.e int,int,int ) so the compiler will try to create the exact same type again.

So it may seem pointless to call DateTime.Now when you can just do [DateTime]::Now but thats not the point, the point was it was running C#, returning an object that you could immediately use in powershell. I threw a linq example in there just to show you a glimpse of the potential.

So how do you do this. You could even do this in V1 with codedom generation but here i’m using PowerShell V2

function run-csharpexpression([string] $expression )
{
$global:ccounter = [int]$ccounter + 1
$local:name  =  [system.guid]::NewGuid().tostring().replace('-','_').insert(0,"csharpexpr")
$local:ns = "ShellTools.DynamicCSharpExpression.N${ccounter}"

$local:template = @"
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;

namespace $ns
{
public static class Runner
{
public static object RunExpression()
{
return [[EXPRESSION]];
}
}
}
"@

$local:source = $local:template.replace("[[EXPRESSION]]",$expression)

add-Type $local:source -Language CsharpVersion3 | out-Null
invoke-Expression ('[' + $local:ns + '.Runner]::RunExpression()')
}

Thanks to Oising http://www.nivot.org for playing around with this when i was building it.

So if i wanted to really turn this into something industrial quality what would i do?

  • try to work out a way that i could create the same anonymous type twice..
  • deal with exceptions well
  • make a version that you can pass in objects from powershell to the expression, and that they could even be put in as fields on the runner class so you could reference them by name from C#
  • Make a version that is designed to be run as part of the pipeline, where the function wrapper would manage the PROCESS block and call the csharp expression once every PROCESS block invocation.
  • I would possibly make a special version of Generics since generics interop is often one of the harder things in Dotnet
  • I’d have it keep a track of all the classes it has made, and have functions to look at them and interact with them and maybe reuse them. Particularly if they are parameterized.

Of course if you were so pathologically inclined you could very easily adapt this to make a VB.NET version too.

Enjoy. And if anybody feels inspired to make a better more industrial quality version i’d love to have a look at it.

Posted in Powershell | 3 Comments »

replacing many grouped regular expression matches in powershell

January 11th, 2010 by Karl

PowerShell has some really good build in language features for dealing with regular expressions -Replace , -Match . Not to mention regex filtering is available to many cmdlets etc, and if thats not enough you can just invoke the powershell Regex classes.

However when dealing with more than the first match.. or where the replace was not just a simple string replace.There are many cases where a simple string substitution was not enough and i really needed to apply some logic at each match to work out what it was to replace it with.

The problem was it took me about 5 or 6 lines of code each time, and broke my “keep everything in the pipeline” goal as well as my workflow. So here is a function to do this. In reality it could be a lot more robust, and could be part of a whole family of such functions carefully sculpted for your regex needs.

More importantly than regex however, this is a good example of refactoring logic in powershell into a one liner, and how using using scriptblock in a “closure” manner where the end user passes in a scriptblock they wrote and gets some automatic variables from the scope of your function. Lets look at the function and an example.

function replace-regexgroup ([regex]$regex, [string]$text ,[scriptblock] $replaceexpression)
{
$regex.Replace($text,{
$thematch = $args[0]
$groupnames = $regex.GetGroupNames()
for ($count = 0; $count -lt ( $thematch.groups.count) ; $count++)
{
set-variable -name $($groupnames[$count]) -visibility private -value $($thematch.groups[$count] )
}
if ($replaceexpression -ne $Null) { &$replaceexpression}
} )
}

So the user passes in the regular expression, the text that they want to do the replace on and a scriptblock which is the expression that will be run for each match, and the result of that expression will be what the each match is replaced with. You can see how i use set-variable to set a variable in the of my function based on the name of each regex match (i really should also do a $1 , $2 , $3 as many people are used to in jquery and such. ) Then i call the scriptblock with &$replaceexpression . I haven’t decided in scenarios like this whether to invoke such scriptblocks with & which will create a child scope for them to run in or rather execute then in my scope with the dotsource operator “.”.

So how do we use this. Well in the first scenario when i made this, i was exporting wiki contents from a desktop app that used HTML stored in a database. I wanted a backup of this content in plain html and it had links such as shown below

$example = @"
<P><a href="wiki://284_636">links to test page 2</a></P>
<P><a href="wiki://109_49">
"@

and i needed to find all those Wiki links and needed to know and transform it based on the two numbers on either side on the _ (in the first case 284 and 636) which i did with the following line of code.

replace-regexgroup 'wiki://(?<wholething>(?<folder>\d+)_(?<page>\d+))' $example { "$folder/$page/index.html" }

You can see that the regex named different groups and that my scriptblock is simply one string with variable expandsion inside using the automagically created variables $folder and $page based on the regex groups.

Here is a link to the script on PoshCode .

I hope that this is more than just a good starting point for a regular expression function but something that helps teach the value of scriptblocks and how they can be used to make reusable code that simplifies your workflow.

-Karl

Posted in PS Refactored, Powershell | 4 Comments »