Saturday, February 17, 2007

Integrating with TextPad

When working with scripts, the most important tool you use is a text/script editor application. From all the ones you can find, and there's a quiet a few, my favorite one is TextPad from Helios Software Solutions. It is powerful and flexible, I just love working with it, my all in one text editor.

I use it for any scripting or text based task, from HTML to PowerShell along with others like [C|VB]Script and many more automation tools. TextPad has everything you need to process and manipulate text. Its great features include the ability to maintain block indents, compare files, automatic code indentation, regular expression based search and replace, macro recording, syntax highlighting, block select mode and much much more.

Additionally, it is lightweight, portable and it's has an unlimited evaluation version (as long as you can bear the nag screen). Among its many features, TextPad has the ability to call external programs (such as compilers).

I'm using it to integrate scripts with their scripting engines, and these days for PowerShell. To integrate PowerShell into TextPad, Run TextPad (Start > Run > textpad) , from the menu choose Configure > Preferences, Click on Tools > Add > Program to add a new program.


Navigate to C:\windows\system32\windowspowershell\v1.0 and add powershell.exe, then click the Apply button. You can click the Help button to discover more info on this dialog option, especially on Tool Parameter Macros. Next, click on the plus sign on Tools to expand it and click on Powershell. Review the available options and make them look like:

Click OK to close the Preferences dialog. If you open the Tools menu item you'll see that CTRL+4 was assigned (in my case) to PowerShell, Cool!. Now, that keyboard shortcut can be used to execute *.ps1 files (which you can always change later).


But wait, there's more (says Russell Brown). When passing parameters to a script you can use the option to "Prompt for parameters" (second screenshot). This will fire the parameters dialog (each time you'll run a script) where you can add additional parameters. An easier way is to use the $Sel parameter macro. It will send the selected text in the active document (when specified inside the parameters field) as additional parameters (this is limited to the first line in a multiple-line selection).


$DOSFile is the same as $File, except that DOS aliases are substituted for any long names in the path, and characters are converted to the DOS (OEM) code set, thus preventing any errors when sending long file names containing spaces. So, from now on, just write the parameters you need inside the script prefixed with the comment sign "#" (to prevent powershell from processing this line), highlight it and press CTRL+4.


Behind the scenes, TextPad will create a .BAT file (in the script directory, which you can safely delete) that includes all the parameters and then executes it.

So grab your own copy and start exploring :-)



PowerShell from Windows explorer

This is a quick one on how to integrate PowerShell into windows explorer's context menu, giving the option to run scripts from windows shell.
Download the reg file, double click it and accept any dialogs. Right click any .ps1file and your
context menu should look similar to:  Double clicking any .ps1 file will still launch in notepad (good security practice).

Thursday, February 15, 2007

Scripting Games 2007 - Live Scores

This little script will parse the scores table on the scripting games website and output the results into the console. It is working kinda slow due to some PS inconsistencies regarding IE automation, so I'll have to keep on checking on it . Meanwhile, get your own results ;-)


$ie=new-object -com internetexplorer.application
while($ie.ReadyState -ne 4) {start-sleep -m 500}

$ds = new-object "System.Data.DataSet" $ds.Tables.Add("score")

1..10 | foreach {
    $table = $ie.document.getElementById("E4")
    $trs | foreach {     
        $tds = $_.GetElementsByTagName("TD")     
        $dr = $ds.Tables[0].NewRow()     
        $tds | foreach {$dr[$x] = $_.innerText}     

$ds.tables | ft * -auto


Sunday, February 11, 2007

Scripting Games 2007 Program

Join The Scripting Games 2007 Program. You can download a PDF with FAQ, games schedule, events and other information. There is also an Introduction to Arrays.

Sunday, February 4, 2007

Abbreviated MMC Snap-ins

As a system administrator, the most frequent windows tools I use are the MMC administrative snap-ins.
Whether locally or for remote computers, snap-ins are all around. You can use them to administer networks, computers, services and other system related tasks. MMC snap-ins can be launched either by clicking on shortcut files or by running them in command line.
The Run dialog (Start > Run) is another place to run them. Most snap-ins support the /computer=computer_name to connect the snap-in to a remote computer.

Personally, the shortest way I use (3 steps) to run snap-ins, is to press WIN+R to invoke the run dialog, type the .msc file name (including extension) and press ENTER. In the endless effort to shorten up the typing process or mouse click to launch applications, I wanted to be able to run .msc files from the run dialog without typing their extensions.

I did some tests including adding the "*.MSC" extension to the windows system %PATHEXT% environment variable and tried to run "eventvew", or some other snap-ins... it didn't work. The "mgmt" suffix for some snap-ins (dnsmgmt.msc,dhcpmgmt.msc etc) was also targeted, on a daily basis its too long. I need to launch snap-ins with abbreviated names, using my own aliases. The solution was to write a script that accept an argument (.msc alias) and fires the relevant snap-in.

Here is the result. Now, system administration with snap-ins, from within the blue console, is only an alias away. You can call the function in various ways:


# with full parameter names msc -snapin dns -machine serverName
# with abbreviated parameter names msc -s dns -m serverIP
# with possitioned parameters msc events serverName Don't forget to include it in your profile or just dot-source it.

function Invoke-MMCSnapIn{    
     $ErrorActionPreference = 0 # SilentlyContinue     
     if(!$snapin) {
         write-warning "Missing snap-in name"
     } else{
             "svcs" {$snapin="services"}
             "events" {$snapin="eventvwr"}
             "dns" {$snapin="dnsmgmt"}
             "dhcp" {$snapin="dhcpmgmt"}
             "device" {$snapin="devmgmt"}
             "comp" {$snapin="compmgmt"}
             default {write-warning "No snap-in defined"}
     if($machine -eq $env:computername) {iex "$snapin.msc"}
     else{iex "$snapin.msc /computer=$machine"}
Set-Alias msc Invoke-MMCSnapIn



Thursday, February 1, 2007

Measure'm all

One of my scripting mottos is to always aspire to script with less steps and at the same time in the fastest way. Basically, you can get from point A to point B in various ways, but in the end, you need to decide which path to choose and how efficient it is.

Back in the VBScript days (seems like a very a long time ago), measuring the time that took your scripts/commands to execute was involved in writing a custom procedure, capturing the date/time before and after the action, and using DATEDIFF function to calculate the difference. Using PS> You can still use the "old" method.

This sample assigns the starting time to $s, executes the main command ($t), and then uses the New-TimeSpan cmdlet to calculate the time difference.


$t=Get-ChildItem "C:\Documents and Settings" -filter *.txt -recurse
New-TimeSpan -start $s

Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 453
Ticks : 4531250
TotalDays : 5.24450231481481E-06
TotalHours : 0.000125868055555556
TotalMinutes : 0.00755208333333333
TotalSeconds : 0.453125
TotalMilliseconds : 453.125


Now, there's no need to write the whole procedure.
There's a built-in cmdlet called Measure-Command specially created for this kind of task, only it is much simpler and shorter:

Measure-Command {Get-ChildItem "C:\Documents and Settings" -filter *.txt -recurse}

Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 452
Ticks : 4525956
TotalDays : 5.238375E-06
TotalHours : 0.000125721
TotalMinutes : 0.00754326
TotalSeconds : 0.4525956
TotalMilliseconds : 452.5956


You can even measure a few lines of code:

Measure-Command {Get-ChildItem "C:\Documents and Settings" -filter *.txt -recurse ;Get-Process; Get-Service }

If you need to test a more complex command structure, consider saving the commands into a .ps1 file and then execute it via Measure-Command:

Measure-Command {& c:\measurec.ps1}

Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 433
Ticks : 4331861
TotalDays : 5.01372800925926E-06
TotalHours : 0.000120329472222222
TotalMinutes : 0.00721976833333333
TotalSeconds : 0.4331861
TotalMilliseconds : 433.1861

That way you can test various scripts/commands that execute procedures using different scripting methods and decide, based on the results, which one to implement. Here is a little teaser. Can you tell which for-loop is faster?

Counting from 1 to 1000?
for($i=0;$i -le 1000;$i++) {$d+=($i*1000)/2}

-or- from 1000 to 1?

for($i=1000;$i -ge 0;$i--) {$d+=($i*1000)/2}


Now you can measure it up, for-loops vs. while-loops and so on :-)