Search

my categories

Blogroll

Debugging Realtime by Ear. Adding one more dimension

January 30th, 2009 by Karl

I am amazed by people who can pick out every single note and chord when listening to music, and others who can totally play by ear. However even the musically inept and tone-deaf of us can detect an odd note, especially if its in a tune we know, but often even in an unknown tune, we can detect an out of place note, that isn’t in the scale, whether we know what a scale is, or even what key the song is in.

So what’s this got to do with debugging? We’ll mostly it’s the real time aspect. You are able to process a lot of information (notes), in context, and are able to discern real-time what is out of place and wrong.

Compare that to typical debugging. You might use checkpoints, and tracing through code, slowing down the execution often a million-fold, tediously stepping through each line of code, looking here and there.
Alternatively you might be processing log output, whether a debug stream in your IDE, console output, or something else. However just getting those messages to somewhere you can display can be hard when threading, and you aren’t in the GUI thread etc.
Additionally you are having to interpret this, often after the fact, and you can often miss things when lots is going on. How often , especially when finding a rare threading bug, are you running something 10 or more times, and maybe logging 10 or so different events each time. Going through the log takes time, and sometimes you miss the cue.

So, is debugging with sounds going to change and revolutionize everything? No its just another tool in a really great toolkit we have these days.

I thank my friend Oisin Grehan (http://nivot.org ) for inspiring this as I don’t think I’ve used sound in debugging since the my  Demoscene  days when I was coding MOD players. Mod Players . So naturaller the tracker syntax has inspired me a bit.

 

So how does this work. Well work out the steps you are listening to, and maybe things you particularly want to catch, play the notes over and over a few times so you know mentality what to expect, then just start running you code, and listen to what actually IS happening, and then maybe at certain times you might make a certain note MEAN something (like middle  C  for TRUE function result and middle A for FALSE), but I typically just use notices to indicate execution flow, and if I want to know some value, I ask windows Speech API to help me out.

function Play-Note([string]$note,[int] $duration = 5)
{
  if (!($note -match '(\d+)')) { $note+='4' };[void]($note -match '([A-G#]{1,2})(\d+)')
  [console]::Beep((440 * [math]::Pow([math]::pow(2,(1/12)),
    (([int] $matches[2]) - 4)* 12 + $( switch($matches[1])
  {  'A'  { 0 }  'A#' { 1 }  'Bb' { 1 }  'B'  { 2 }  'C'  { 3 }  'C#' { 4 }  'Db' { 4 }
     'D'  { 5 }  'D#' { 6 }  'Eb' { 6 }  'E'  { 7 }  'F'  { 8 }  'F#' { 9 }  'Gb' { 9 }
     'G'  { 10 } 'G#' { 11 } 'Ab' { 11 }
  }))),$duration * 100 )
}

So two things. I’ve based the notes on common tracker syntax including the octave. so middle A is A4 , then you have things like F#3 etc. however if as with everything PowerShell we want pithy, so if you don’t put an octave number then it will be 4 by default.

play-note C ; play-note Eb ; play-note “C#”

also i included a duration, so if the want the note to be anything but the default half a second put that as a parameter

play-note Eb4 20

and you’ll get an E flat for 2 whole seconds. You may ask why I don’t use seconds or milliseconds, because those are our official measurements in this 1,000,000 3 grouped western world. Well the reason is pithiness (something i love in my scripts, but aren’t good about when it comes to blogging). Typically i want a note between say 300 milliseconds and 5 seconds. so if i used milliseconds i’d always have to have those 2 or 3 extra zeros, while if i used seconds I’d be doing things like 0.4 and 1.5. If Japanese and Chinese we often communicate number differently, and group them differently. so there is a word for 10,000 , so to say 15 thousand you may say 1 (character for 10,000) 5.

So what about voice. You can use a very simple function using the SAPI COM objects such as:

function Speak-words ([string]$words,[bool]$pause = $true)
{   $flag = 1
    if ($pause) {$flag = 2}
    $voice = new-Object -com SAPI.spvoice
    $voice.speak($words, [int] $flag)
    # 2 means wait until speaking is finished to continue
}

Typically though i don’t create a $voice everytime , but kept a reference somewhere , like in my V2 module. Others however have done more impressive things with the voice in powershell ( http://poshcode.org/667 | http://huddledmasses.org/powershell-speaks/ ).

So now you may want a way to play more notes and speak more words together, in a pithy line. you can just use play-notes

function Play-Notes
{
$defaultduration = 5;if($args[0] -is [int]) {$defaultduration = $args[0]}
for($i = 0;$i -lt $args.length;$i++)
 {    $duration = $defaultduration
    if ($i -lt $args.length-1) { if ($args[$i+1] -is [int]) {$duration = $args[$i+1] } }
    if ($args[$i] -is [string]) {
        if ($args[$i].startswith("!")) { speak-words $args[$i].replace('!','') } else
        { play-note $args[$i] $duration }
        }
 }
}

And with this you can simply pass in a list of notes, which will be played with a default duration, unless you choose to specify a duration after the note.

play-notes A B C 20 E 10 B 10

play-notes F5 2 E5 2 D5 2 C5 2 B5 2 A5 2 G 4 F5 2 E5 2 D5 2 C5 2 B5 2 A5 2 G 4

If you want to change the default duration to reduce the redundancy above, just put that number as the first parameter

play-notes 2 F5 E5 D5 C5 B5 A5 G 4 F5 E5 D5 C5 B5 A5 G 4

and finally if you want some speaking in there, just have your string start with an exclamation mark!

play-notes "!here we go now" Db5 Db Eb Gb Ab "C#" 6 !YEAH

But of course most of the time you will have speaking, you’ll want it to say something you don’t know like a variable or the results of a formula.

play-notes A!$([datetime]::now) C

So you can get all these functions together at poshcode. ( Script | Download )  . We’ll time will tell if this will stay a habit of mine or be a fad. Additionally if you wanted to take this seriously you’d probably want to use something better than console.beep , maybe you’d use a full on MOD engine like http://fmod.org/ and having it running iringn a different process, and have a very cpu lightweight IPC going on, and different threads could play different channels, so between threads you could debug via Chords if you really have the ear for it.

WARNING, NOT A CUBICLE FRIENDLY DEBUGGING TECHNIQUE WITHOUT HEADPHONES UNLESS YOU WANT YOUR COLLEGUES TO DEBUG YOU.

Enjoy,

Karl

Posted in Powershell, pscom | No Comments »

PowerSMUG – Syncronize folders on your machine with Smugmug.

January 12th, 2009 by Karl

In ShellTools most of you were familiar with only Tobias Weltner and Myself, however behind the scenes was a critical cofounder – Eddie Hadjes. Below is a script Eddie wrote a few months back to synchronize data between your local folders and the excellent SmugMug web album service. You can always get the latest version and info on our wiki.

Script @ PoshCode: View Script | Download

Share on Facebook

 

—-

# PowerSmug photo sync script v1.0
# This PowerShell script will syncronize a folder of images with a users SmugMug account
# Please set the appropriate variables in the User Defined Variables region
# For more information visit http://shelltools.wik.is/Other_Projects/PowerSmug
#
# Images are uploaded to a gallery with the same name as the folder they are contained in.
# All folders below the Photo Directory path and the images they contain will be uploaded to SmugMug
# Folders that end in _ are ignored, so if you don't want to sync a folder with SmugMug, just add an underscore at the end
#
# Copyright 2008 Shell Tools, LLC

#Region User Defined Variables

$ApiKey = 'uVUvCbXP3f6MgO9wIRJn21YCIgEidVly'
$EmailAddress = '[SmugMug Email]'
$Password = '[SmugMug Password]'
$PhotoDirectory = '[Path To Photos]'
$filesToInclude = @('*.jpg','*.png','*.tif','*.cr2')
$worldSearchable = 1
$smugSearchable = 1

# Professional Accounts Only
$watermark=0
$watermarkId=0

#Email Variables
$smtpServer = '[SMTP Server]'
$smtpUser = '[SMTP User]'
$smtpPassword = '[SMTP Password]'
$smtpFrom = 'PowerSmug@shelltools.net'

#EndRegion

#Region Global Variables

$baseUrl = 'http://api.smugmug.com/hack/rest/1.2.0/'
$userAgent = 'PowerSmug v1.0'
$logFile = 'PowerSmug.log'
$script:SessionId = $null
$script:startStringState = $false
$script:valueState = $false
$script:arrayState = $false
$script:saveArrayState = $false
$script:datFileDirty = $false
$script:datFile = @()
$script:albumList = $null
$script:imageList = $null

#EndRegion

#region Helper Functions

function SendEmail([string] $to, [string] $subject, [string] $msg)
{
    $smtpMail = new-Object System.Net.Mail.SmtpClient $smtpServer
    $smtpMail.DeliveryMethod = [System.Net.Mail.SmtpDeliveryMethod]'Network'
    $smtpMail.Credentials = new-Object System.Net.NetworkCredential $smtpUser, $smtpPassword

    $smtpMail.Send($smtpFrom, $to, $subject, $msg)
}

function Get-MD5([System.IO.FileInfo] $file = $(Throw 'Usage: Get-MD5 [System.IO.FileInfo]'))
{
    # This Get-MD5 function sourced from:
    # http://blogs.msdn.com/powershell/archive/2006/04/25/583225.aspx
    $stream = $null;
    $cryptoServiceProvider = [System.Security.Cryptography.MD5CryptoServiceProvider];
    $hashAlgorithm = new-object $cryptoServiceProvider
    $stream = $file.OpenRead();
    $hashByteArray = $hashAlgorithm.ComputeHash($stream);
    $stream.Close();

    ## We have to be sure that we close the file stream if any exceptions are thrown.
    trap
    {
        if ($stream -ne $null) { $stream.Close(); }
        break;
    }

    # Convert the MD5 hash to Hex
    $hashByteArray | foreach { $result += $_.ToString("X2") }

    return $result
}

function SendWebRequest([string]$method, $queryParams, $ssl = $false)
{
    $url = $baseUrl
    if ($ssl -eq $true) {
        $url = $url.Replace("http", "https")
    }

    $url += "?method=$method"

    foreach ($key in $queryParams.Keys) {
        $url += "&$key=" + $queryParams[$key]
    }

    $wc = New-Object Net.WebClient

    $wc.Headers.Add("user-agent", $userAgent)
    [xml]$webResult = $wc.DownloadString($url)

    CheckResponseForError $webResult

    return $webResult.rsp
}

# Adds image information to our data file
function AddFile ([System.IO.FileInfo]$file, $smugId) { 

    $a = 1 | Select-Object Name, SmugId, LastModifiedTime;
    $a.Name = $file.Name
    $a.SmugId = $smugId
    $a.LastModifiedTime = $file.LastWriteTimeUtc.ToString()

    $script:datFile += $a
#    $script:datFileDirty = $true

    #we are now saving the file after each upload to prevent duplicates when there is a failure
    AppendDataFile $datFilePath $a
}

# writes the data file to the local directory
# each directory will have a data file with information for images contained in it
function SaveDataFile($filePath, $clearFile=$true)
{
    if ($script:datFileDirty -eq $false) { $script:datFile = @(); return }

    [System.IO.File]::Delete($filePath)

    $sortedFile = $script:datFile | sort-Object -property Name
    $sortedFile | Export-Csv $filePath 

    $script:datFileDirty = $false

    # mark the file as hidden
    ls $filePath | foreach { $_.Attributes = $_.Attributes -bor [System.IO.FileAttributes]::Hidden }

    if ($clearFile -eq $true) {
        # clear the variable
        $script:datFile = @()
    }
}

# appends a new row to the data file
function AppendDataFile($filePath, $record)
{
    if (test-Path $datFilePath) {
        $newLine = [System.String]::Format('{0},{1},"{2}"', $a.Name, $a.SmugId, $a.LastModifiedTime)
        Add-Content $filePath $newLine
    }
    else
    {
        $script:datFileDirty = $true
        SaveDataFile $filePath $false
    }
}

# ensure our web request was successful
function CheckResponseForError($xmlResponse)
{
    if ($xmlResponse.rsp.stat -eq 'fail')    {
        throw $webResult.rsp.err.msg
    }
}

#endregion

#region Login/Logout

function Login()
{
    if ($script:SessionId -ne $null) { return }

    $ht = @{APIKey=$ApiKey;EmailAddress=$EmailAddress;Password=$Password}
    $loginResult = SendWebRequest "smugmug.login.withPassword" $ht $true

    if ($loginResult.stat -eq "ok") {
        $script:SessionId = $loginResult.Login.Session.id
    }
    else {
        Throw "Error on login: " + $loginResult.Message
    }
}

function Logout()
{
    if ($script:SessionId -eq $null) { return }

    $ht = @{SessionID=$script:SessionId}
    $logoutResult = SendWebRequest "smugmug.logout" $ht
}

#endregion

#region Images

# this method is only needed if we cannot find the PowerSmug.dat file.
# preventing us from uploading duplicate images
function GetImage($name, $album)
{
    Login 

    $image = $script:imageList.Images | Where-Object { $_.FileName -eq $name }
    if ($image -ne $null) { return $image }

    # we are using heavy because we need the file name
    $ht = @{SessionID=$script:SessionId;AlbumID=$album.id;Heavy=1;AlbumKey=$album.Key}
    [xml]$script:imageList = SendWebRequest "smugmug.images.get" $ht

    return $script:imageList.Images.Image | Where-Object { $_.FileName -eq $name }
}

function UploadFile($file, $albumName)
{
    $album = GetAlbum $albumName
    # $image = GetImage $file.Name $album    
    # if ($image -ne $null) { return $image.id }

    $url = "http://upload.smugmug.com/" + $file.Name

    $wc = New-Object Net.WebClient

    $hash = Get-MD5 $file

    $wc.Headers.Add("user-agent", $userAgent)
    $wc.Headers.Add("ContentMd5", $hash)
    $wc.Headers.Add("X-Smug-FileName", $file.Name)
    $wc.Headers.Add("X-Smug-AlbumID", $album.id)
    $wc.Headers.Add("X-Smug-SessionID", $script:SessionId)
    $wc.Headers.Add("X-Smug-Version", "1.2.0")
    $wc.Headers.Add("X-Smug-ResponseType", "REST")
    $webResult = $wc.UploadFile($url, "PUT", $file.FullName)
    [xml]$webResult = [System.Text.Encoding]::ASCII.GetString($webResult)

    CheckResponseForError $webResult

    return $webResult.rsp.Image.id
}

function UploadExistingFile($file, $id)
{
    Login 

    $url = "http://upload.smugmug.com/" + $file.Name

    $wc = New-Object Net.WebClient

    $hash = Get-MD5 $file

    $wc.Headers.Add("user-agent", $userAgent)
    $wc.Headers.Add("ContentMd5", $hash)
    $wc.Headers.Add("X-Smug-FileName", $file.Name)
    $wc.Headers.Add("X-Smug-ImageID", $id)
    $wc.Headers.Add("X-Smug-SessionID", $script:SessionId)
    $wc.Headers.Add("X-Smug-Version", "1.2.0")
    $wc.Headers.Add("X-Smug-ResponseType", "REST")
    $webResult = $wc.UploadFile($url, "PUT", $file.FullName)

    [xml]$webResult = [System.Text.Encoding]::ASCII.GetString($webResult)

    CheckResponseForError $webResult

    return $webResult.rsp
}

#endregion

#region Album

function GetAlbumList($forceRefresh=$false) {
    Login

    if ($forceRefresh -eq $false) {
        if ($script:albumList -ne $null) { return }
    }

    $ht = @{SessionID=$script:SessionId}
    $script:albumList = SendWebRequest "smugmug.albums.get" $ht
}

function GetAlbum($name)
{
    #before we create an album ensure it doesn't already exist
    GetAlbumList

    $album = $script:albumList.Albums.Album | Where-Object { $_.Title -eq $name }
    if ($album -ne $null) { return $album } 

    Write-Host "Creating album: $name"
    $ht = @{SessionID=$script:SessionId;Title=$name;CategoryID=0;Public=0;
    X2Larges=0;X3Larges=0;Originals=0;Watermarking=$watermark;
    WatermarkID=$watermarkId;WorldSearchable=$worldSearchable;SmugSearchable=$smugSearchable}
    $result = SendWebRequest "smugmug.albums.create" $ht

    # be sure we refresh the album list after creation
    GetAlbumList $true

    return $result.Album
}

#endregion

#region Process File

function ProcessFile([System.IO.FileInfo]$file, $albumName)
{
    $photoObject = $script:datFile | Where-Object { $_.Name -eq $file.Name }

    if ($photoObject -ne $null) {
        if ($photoObject.LastModifiedTime -ne $file.LastWriteTimeUtc.ToString()) {
            # file has been modified, so re-upload the file
            write-Host "Updating existing file: " $file.FullName
            UploadExistingFile $file $photoObject.SmugId
            $photoObject.LastModifiedTime = $file.LastWriteTimeUtc.ToString()

            # mark the dat file as dirty so it will be saved after processing this folder
            $script:datFileDirty = $true
        }
    }
    else {
        #file doesn't exist in local file, upload to SmugMug
        write-Host "Uploading new file: " $file.FullName
        $id = UploadFile $file $albumName
        AddFile $file $id
    }
}

#endregion

#region Main Script

# this section will look through all sub-directories of $PhotoDirectory and upload the images to SmugMug
Get-ChildItem -recurse $PhotoDirectory | Where-Object { $_.Attributes -band [System.IO.FileAttributes]::Directory } | foreach {
    # don't process folders that end in _
    if ($_.FullName.EndsWith("_") -eq $false) {
        $datFilePath = $_.FullName + "\PowerSmug.dat"
        if (test-Path $datFilePath) {
            # casting as array to ensure we have an array returned
            [array]$script:datFile = import-Csv $datFilePath
        }

        $albumName = $_.FullName.Remove(0, $PhotoDirectory.Length).Trim('\')

        $path = $_.FullName + "\*"
        foreach ($file in get-ChildItem $path -include $filesToInclude) {
            ProcessFile $file $albumName
        }
        SaveDataFile $datFilePath
        $script:imageList = $null
    }
}

Logout

$date = Get-Date
Write-Host "Script Completed: $date"

trap [Exception] {
        $date = Get-Date
        $Msg = $date.ToString() + " ; " + $_.Exception.GetType().FullName + " ; " + $_.Exception.Message
        Add-Content $logFile $Msg
        SendEmail $EmailAddress "PowerSmug Error" $Msg
        break
    }

#endregion

—–

Posted in Powershell, pscom | No Comments »

PowerShell Analyzer Refresh for PSV2 + CTP3 advanced function features.

January 8th, 2009 by Karl

Though we don’t have intentions to carry developing PowerShell Analyzer much in the future, there are a number of improvements in my personal fork, and we want to make sure that it keeps its shelf life by updating it for PowerShell V2. Surprisingly we are still getting hundreds of downloads a day so we want to make sure that those who prefer PSA can still keep using it and also take advantage of the features I use day in and day out. We’ll probably release some new builds within the next couple of weeks, but will post some screenshots and maybe videos until then. We hope that will minimal effort keep PSA the best free PowerShell tool. However if want a tool that is definitely worth paying for check out PowerShell Plus at its new home at Idera – http://www.idera.com/Products/PowerShell/

So here is a screenshot of PowerShell Analyzer running with PowerShell V2 CTP3. The new features are all related to the help features of advanced Functions.

  • Region support for multiline comments <# #>
  • Syntax Coloring for help documenting keywords (i.e.  .DESCRIPTION )
  • Code Completion for help documenting keywords.
  • Rich Rendering of advanced function help from get-help in HTML (any advanced function that is in the RunSpace)

1712842

So there. you go. However the help rendering is only in our really old 3 year old Help rendering engine. If you like it wait for our HelpFusion app which will be separate and be able to be used independently or from any PowerShell host. Some of you have seen it, but the rest of you will have to wait until we finish rewriting it for WPF.

Karl

Posted in Powershell, Powershell Analyzer, pscom | 2 Comments »

This is your Admin life. You HAVE to script PowerShell

January 6th, 2009 by Karl

So i was listening to that Dust Brother’s Tyler Durden song from fight club, and PowerShell lyrics started jumping into my head. We’ll most were fleeting before i could capture them, but i did come up with something at least tacky, and fun to some. No offense to anybody. Anyway here is the original song. Listen to it once to get the picture, then a second time while reading my lyrics. Here is a link to the original lyrics.


This is your Admin Life

And you open the door and you step inside
We’re inside our servers

Now imagine that that Blue Screen is a white ball of healing light
That’s right, that exception itself is a white ball of healing light

I don’t think so

This is your job , Good to the last cpu cycle.
It doesn’t get any better than this.
This is your job and its ending one click at a time.

This isn’t your favourite tech conference. This isn’t no geek class.
Where you are now, you can’t even imagine what the bottom will be like
Only after disaster, will your server need resurrected.
Its only after you’ve lost everything that you’ll learn to script anything.
Nothing is static, everything is Dynamic
Without no agile script, it’s all falling apart.

This is your job.
(Without PowerShell)
It doesn’t get any better than this.
This is your job
And its ending one click at a time.

You are not a beautiful and unique engineer.
You are the same decaying GUI based admin  as everybody else.
We are all part of the same time consuming life draining Slavehood
We are the all cringing,ever working info-saviours of the world

You are not your dollarstore tech certification.
You are not your Antivirus failure.
You are not your dumbed down GUI management tools.

You are not your HR employee primary key
You are not your Active Directory login.
You are not your CIO’s latest tech fad.
You are not your hungover 70’s unix shell script.

You have to Code PowerShell.
You have to Code PowerShell.

You have to realize that someday GUI admins will be unemployed
Until you know that, you are useless.

I say never let me be GUI dependant
I say may I never be content.
I say deliver me from MMC console ripoffs.
I say deliver me from VBscript.
I say deliver me from misunderestimating linux zealots.
I say you have to PowerShell
I saw grow, and let the scripts run where they may

This is your job.
(Without PowerShell)
It doesn’t get any better than this.
This is your job
And its ending one click at a time.

You have to Code PowerShell
You have to Code PowerShell

I want you to script me as hard as you can.
I want you to script me as hard as you can.

Welcome to #powershell Club. If this is your first night, you have to code.

Enjoy – Karl

Posted in Powershell, pscom | 7 Comments »

PowerShell Analyzer like execution hotkeys for PS CTP3 ISE.

January 3rd, 2009 by Karl

PowerShell CTP3 ISE – Integrated Scripting environment has inherited many ideas and features from PowerShell analyzer including multiple runspaces,editors, a smaller immediate input area and output pane, however it doesn’t have the output visualizers of PSA nor the super fast RTS like execution control of PSA.

However Microsoft in their wisdom has made ISE rather extensible through the $PSISE variable, and many people already have added some very cool functionality to ISE through these.

When I first demo’d what was then MSH analyzer to Microsoft back in the first few months of 2006, the feature that seemed to stand out the most to the team was the ability to select an area of code and just run that. Thankfully that level of execution control is now in ISE as F6, but I wanted more, so i’m going to share with you a script that build a few months ago to add a couple of features.

F7 run the current physical line.

this basically will run the line where the caret current is at.

Real Time Strategy like control.. CTRL 1 , CTRL 2 etc

This here allows you to use comments to create regions, then EXECUTE those regions with a simple hotkey. I use this extensively. Often i am working on building a function, so I edit the function, press Ctrl 1 to apply the function, then if that was successful, press Ctrl 2 , then maybe Ctrl 3 to run some tests to make sure my changes to the function are what i am expecting.

This gives me a great AGILITY , putting what Jeffery Snover calls the Admin Development Model , but which is really REPL(Repeat Evaluate, Print , Loop ) rediscovered, on agile steroids.

function invoke-caretline
{
invoke-expression $([Regex]::Split($psISE.CurrentOpenedFile.Editor.text,"`r`n" )[$psISE.CurrentOpenedFile.Editor.caretline-1])
}
$psISE.CustomMenu.Submenus.Add("Run single line", {invoke-caretline} ,  'f7')
function invoke-region([int] $num)
{
$ed = $psISE.CurrentOpenedFile.Editor
$lines = [Regex]::Split($ed.text,"`r`n" )
$foundfirst = -1
$foundlast = -1
for($count = 0;$count -le $lines.length-1;$count++)
 {
   if ($lines[$count].startswith("#region") -and $lines[$count].contains("@$num"))
   { $foundfirst = $count;break}
 }
 if($foundfirst -gt -1)
 {
 for ($count = $foundfirst; $count -le $lines.length-1;$count++)
    {
    if ($lines[$count].startswith("#endregion") )
   { $foundlast = $count;break}
    } 

 if ($foundlast -gt -1)
   {
     $torun = ""
     $lines[$foundfirst..$foundlast] | % { $torun+=$_ + "`r`n"}
     invoke-expression $torun
   }
 } 

}
 $psISE.CustomMenu.Submenus.Add("run region 1", {invoke-region 1 },  'ctrl+1')
 $psISE.CustomMenu.Submenus.Add("run region 2", {invoke-region 2 },  'ctrl+2')
 $psISE.CustomMenu.Submenus.Add("run region 3", {invoke-region 3 },  'ctrl+3')
 $psISE.CustomMenu.Submenus.Add("run region 4", {invoke-region 4 },  'ctrl+4')
 $psISE.CustomMenu.Submenus.Add("run region 5", {invoke-region 5 },  'ctrl+5') 

Script @ PoshCode: View Script | Download

Sometime I’ll wrap all this up into a module, and add other PowerShell Analyzer-like functionality such as running the current PARAGRAPH. So often in an earlier PSA, and in SQL Query Analyzer, i’m highlighting again and again the SAME paragraph query and running it over and over again. Being able to just run the current paragraph saves that time.

Technorati Tags: ,,,

Posted in PSV2, Powershell, pscom | 6 Comments »

I love/hate Windows Live Writer

January 3rd, 2009 by Karl

I love Windows Live writer and its features. I just hate the small surface of installation. So I have it on my vista Laptop, which was great until I took it off the corp network, and Livewriter stores the configs in my unsynced locations and crashes. So I think lets put it on my other laptop, but its 64bit no go, so lets put it on my dev machine – argg that’s windows 2008 so no go again, then I try to put it on my dev VM, but that is windows server 2003, again a no go. I need to get back to blogging. My blog posts and ideas written in OneNote is just building up (I love OneNote). I’m setting up a XP VM solely for livewriter. That’s how much I love it. I’m willing to put up with its pedantic and give it its own XP VM empire if it will just let me visit and blog.

Posted in Powershell | 2 Comments »