2014-12-09

Day of the Tentacle Special Edition



I was initially super-keen on the idea of a Day of the Tentacle remake/special edition, but it's already pretty much perfect - distinctive look, voice acting that fits perfectly, a brilliant soundtrack. So, maybe just leave it in peace? That said, I'm sure I'll end up playing it anyway - I love DotT to bits, after all.

Now, as for Grim Fandango, that needed a bit of a control scheme overhaul so the new edition of that could really come out well.

jQuery can be unbelievably handy and concise

Adding selectable table rows in jQuery

The short bit of jQuery consists of the following:
  • Adds a .click() function to any tr elements inside a tbody element to toggle the addition of the selected class whenever a row is clicked.
  • Next, another .click() to give a link with the ID selectAll the ability to toggle all rows at once.
  • Finally, one more .click() attached to the ID clearSelected that will deselect any rows currently selected.
In this case any tr elements inside a tbody element are selected, but this could be refined using IDs or Classes if there are multiple tables on the page.

$(document).ready(function() {
    $('tbody tr').click(function() {
        $(this).toggleClass('selected');
    });
    $('#selectAll').click(function() {
        $('tbody tr').toggleClass('selected');
    });
    $('#clearSelected').click(function() {
        $('tbody tr').removeClass('selected');
    });
});


The HTML for each button just needs to reference the chosen ID. A bit of CSS can make it look more like a button than a bog standard link if you're so inclined (I certainly was...)

<a href='#' id='selectAll' class='button'>Select All</a>
<a href='#' id='clearSelected' class='button'>Clear Selected</a>

2014-08-16

This NUC is absolutely tiny

This thing is bloody tiny, a really tidy little package.


Of course, I can't find a screwdriver small enough to remove the tiny screws securing the 2.5" bracket so I'm stuck for the moment until I work out where my Jewelers' screwdrivers are...

[Edit] I'm an absolute muppet. The SSD just slides in from the front, no need to unscrew anything. I'll put this down to either too much or too little coffee this morning. Yeesh.

New toys to play with over the weekend

Some new gear to play with, just in time for what looks to be a wet weekend.




The MicroServer isn't actually new; it's just been sitting on my floor for a couple weeks waiting for me to order more RAM so it can actually do, you know, anything.


The NUC is going to be a Home Theater PC - normally, I'd be sticking Debian on it without a second though but I want to run the Foxtel Go app on it and that means Windows. Oh well. On the upside, if the NUC works out as the new HTPC, that frees up the Mac Mini that's currently doing that job.

2014-07-26

Photos from 2014 International Ice Hockey Australia

For the record  Team USA prevailed 5-4 over Team Canada in OT after coming back from being 0-2 down in the first period. Just like last year it was a really good night, complete with the sort of over-the-top production that you'd expect.

The first of many fights breaks out.


At one stage it was standing room only in the penalty boxes...
 

Going into OT

USA scores the winning goal and goes nuts celebrating while being buried in streamers.





2014-07-03

Word of the Day

ul·ti·mo
/ˈəltəˌmō/
adjective dated
adjective: ultimo; symbol: ult.; symbol: ulto
  1. of last month.
    "the 3rd ultimo"
Origin: from Latin ultimo mense ‘in the last month.’


Doesn't it just add so much to a sentence? Replacing, for example, "The 27th of last month" with "The 27th Ultimo" lends a touch of class. Or something close to class, at any rate...

2014-07-02

Notable quotable

"It is the mark of an educated mind to be able to entertain a thought without accepting it."

- Aristotle



Amen, brother...

Retrieving values from XML with PowerShell


This PowerShell script looks up  and returns results from a mini-database that uses XML as its back-end. For the actual program that edits and returns results graphically, I used Java - this was an exercise in learning PowerShell's XML functions. As can be seen below, the in-built XML handling makes working with XML files very straightforward indeed.

The structure of the XML file I'm using to test is:

<?xml version="1.0" encoding="UTF-8"?>
<recordList>
    <record id="0">
        <title>Some Title</title>
        <category>Some Cat</category>
        <notes>Some Notes</notes>
    </record>
    <record id="1">
        <title>Great Expectations</title>
        <category>Categorical</category>
        <notes>Egghead likes his bookie-wook</notes>
    </record>
</recordList>


Each record element has an associated ID attribute and contains the elements Title, Category and Notes.


Now for the script itself. First, define the parameters accepted from the command line. Only search type is mandatory as the returnAllRecords function (called by passing 'all' as the parameter) doesn't require a search term.

[CmdletBinding()]
param(
    [parameter(Mandatory = $true)]
    [ValidateNotNullOrEmpty()]
    [string]$searchType,
    [parameter(Mandatory = $false)]
    [ValidateNotNullOrEmpty()]
    [string]$searchTerm
)



Create an object and load the XML file - in this case: c:\temp\test1.xml:

[System.Xml.XmlDocument]$xmlFile = New-Object System.Xml.XmlDocument
$xmlFile.load("c:\temp\test1.xml")



This function performs lookup by Title. One variable is expected - the search term.
 

Select the /recordList/record node, then loop through each record, checking if the title is like the search term. The * act as wildcards.
 

When each record is read in, the various elements can be read by appending the name to the end of the object, joined with a dot - in this case, title, category and notes
 

PowerShell uses the ` as the escape character - the usual \n, \t and \r from C and similar languages becomes `n, `t and `r.
 

The quotes in the write-host output aren't strictly needed in this case - they're mainly there to provide a visual distinction.

function lookupByTitle ($searchTermTitle) {
    $counter = 0
    $lookup = $xmlFile.SelectNodes("/recordList/record")
    write-host Results for $searchTermTitle in Title:
    foreach ($record in $lookup) {
        if ($record.title -like "*$searchTermTitle*") {
            write-host "Title:`t" $record.title "`t`tCategory:`t" $record.category "`t`tNotes:`t" $record.notes`n
            $counter++
        }
    }
    write-host "Displayed:"$counter "records.`n"
}



Category lookups are handled by a nearly identical function as for titles - category is appended to the object in place of title:

function lookupByCategory ($searchTermCategory) {
    $counter = 0
    $lookup = $xmlFile.SelectNodes("/recordList/record")
    write-host Results for $searchTermCategory in Category:
    foreach ($record in $lookup) {
        if ($record.category -like "*$searchTermCategory*") {
            write-host "Title:`t" $record.title "`t`tCategory:`t" $record.category "`t`tNotes:`t" $record.notes`n
            $counter++
        }
    }
    write-host "Displayed:"$counter "records.`n"
}




This function looks up a record by its ID - in this case, ID isn't an element, it's an attribute of the record element (e.g., <record id="9">), so the method to look it up is a little different.


First off, as the value being passed is a string, it needs to be converted to an integer. To avoid throwing an error when attempting to convert a non-numeric value, the custom function isNumeric() is called to check (this function is declared later in the script). If it isn't a number, no conversion is attempted and an error message is shown. An alternative would be to wrap the line $recordID = [int]$searchTermRecord in a try/catch block.

  • To find the number of records, Count is appended to the element path.
  • In order to allow for a record ID of 0, 1 is subtracted from the value of $totalRecords before testing.
  • A specific record's values are returned by passing the ID in brackets to the full path of the record element node, for example: $xmlFile.recordList.record[1].title

function lookupByRecord ($searchTermRecord) {
    if (isNumeric($searchTermRecord) -is True) {
        $recordID = [int]$searchTermRecord
        $totalRecords = $xmlFile.recordList.record.Count
        write-host "`nTotal records: " $totalRecords
        write-host "Looking up record with ID: " $searchTermRecord`n
        if ($searchTermRecord -gt $totalRecords-1 -or $searchTermRecord -lt 0) {
            write-host "No such record.`n"
        }
        else {
            write-host "Title:`t" $xmlFile.recordList.record[$recordID].title`t`t"Category:`t" $xmlFile.recordList.record[$recordID].category`t`t"Notes:`t" $xmlFile.recordList.record[$recordID].notes`n
        }
    }
    else {
        write-host "Integer expected.`n"
    }
}




The simplest lookup involves returning all records. This function loops through every record and returns the ID, Title, Category and Notes.

function returnAllRecords {
    write-host `n"Returning all records:"`n
    $returnRecords = $xmlFile.SelectNodes("/recordList/record")
    foreach ($record in $returnRecords) {
        write-host Record ID: $record.id`n`tTitle: $record.title`n`tCategory: $record.category`n`tNotes: $record.notes`n
    }
}



The isNumeric function is used by lookupByRecord to test if the passed value is a number or not, using a short Regular Expression. Integers are accepted, as are floating point numbers (anything after the floating point is dropped during the conversion to integer).

NB: http://www.regexr.com/ is a good place to test RegEx before using in scripts.

function isNumeric ($testValue) {
    return $testValue -match "^[\d\.]+$"
}



After declaring all the functions, do a short if/elseif/else to see what sort of search we're doing, then call the function.

As search term isn't mandatory, check if one exists before calling lookupByTitle, lookupByCategory or lookupByRecord.



if ($searchType -like "all") {
    returnAllRecords
}
elseif ($searchType -like "title") {
    if (!$searchTerm) {
        write-host "Search term required for search type: Title.`n"
    }
    else {
        lookupByTitle -searchTermTitle $searchTerm
    }
}
elseif ($searchType -like "category") {
    if (!$searchTerm) {
        write-host "Search term required for search type: Category.`n"
    }
    else {
        lookupByCategory -searchTermCategory $searchTerm
    }
}
elseif ($searchType -like "record") {
    if (!$searchTerm) {
        write-host "Search term required for search type: Record.`n"
    }
    else {
        lookupByRecord -searchTermRecord $searchTerm
    }
}
else {
    write-host "Invalid search type.`n"
}



And the complete script:

1:  <#  
2:  .SYNOPSIS  
3:  Return records from XML-based database  
4:  .DESCRIPTION  
5:  Search by ID (Record), Title, Category or return all records  
6:  .PARAMETER searchType  
7:  The type of search to perform: all/title/category/record  
8:  .EXAMPLE  
9:  .\readXml all  
10:  .EXAMPLE  
11:  .\readXml title "Some Title"  
12:  #>  
13:    
14:  [CmdletBinding()]  
15:  param(  
16:       [parameter(Mandatory = $true)]  
17:       [ValidateNotNullOrEmpty()]  
18:       [string]$searchType,  
19:       [parameter(Mandatory = $false)]  
20:       [ValidateNotNullOrEmpty()]  
21:       [string]$searchTerm  
22:  )  
23:    
24:  [System.Xml.XmlDocument]$xmlFile = New-Object System.Xml.XmlDocument  
25:  $xmlFile.load("c:\temp\test1.xml")  
26:    
27:  function lookupByTitle ($searchTermTitle) {  
28:       $counter = 0  
29:       $lookup = $xmlFile.SelectNodes("/recordList/record")  
30:       write-host "`nResults for" $searchTermTitle "in Title:`n"  
31:       foreach ($record in $lookup) {  
32:            if ($record.title -like "*$searchTermTitle*") {  
33:                 write-host "Title:`t" $record.title "`t`tCategory:`t" $record.category "`t`tNotes:`t" $record.notes`n  
34:                 $counter++  
35:            }  
36:       }  
37:       write-host "Displayed:"$counter "records.`n"  
38:  }  
39:    
40:  function lookupByCategory ($searchTermCategory) {  
41:       $counter = 0  
42:       $lookup = $xmlFile.SelectNodes("/recordList/record")  
43:       write-host "`nResults for" $searchTermCategory "in Category:`n"  
44:       foreach ($record in $lookup) {  
45:            if ($record.category -like "*$searchTermCategory*") {  
46:                 write-host "Title:`t" $record.title "`t`tCategory:`t" $record.category "`t`tNotes:`t" $record.notes`n  
47:                 $counter++  
48:            }  
49:       }  
50:       write-host "Displayed:"$counter "records.`n"  
51:  }  
52:    
53:  function lookupByRecord ($searchTermRecord) {  
54:       if (isNumeric($searchTermRecord) -is True) {  
55:            $recordID = [int]$searchTermRecord  
56:            $totalRecords = $xmlFile.recordList.record.Count  
57:            write-host "`nTotal records: " $totalRecords  
58:            write-host "Looking up record with ID: " $searchTermRecord`n  
59:            if ($searchTermRecord -gt $totalRecords-1 -or $searchTermRecord -lt 0) {  
60:                 write-host "No such record.`n"  
61:            }  
62:            else {  
63:                 write-host "Title:`t" $xmlFile.recordList.record[$recordID].title`t`t"Category:`t" $xmlFile.recordList.record[$recordID].category`t`t"Notes:`t" $xmlFile.recordList.record[$recordID].notes`n  
64:            }  
65:       }  
66:       else {  
67:            write-host "Integer expected.`n"  
68:       }  
69:  }  
70:    
71:  function returnAllRecords {  
72:       write-host `n"Returning all records:"`n  
73:       $returnRecords = $xmlFile.SelectNodes("/recordList/record")  
74:       foreach ($record in $returnRecords) {  
75:            write-host Record ID: $record.id`n`tTitle: $record.title`n`tCategory: $record.category`n`tNotes: $record.notes`n  
76:       }  
77:  }  
78:    
79:  function isNumeric ($testValue) {  
80:       return $testValue -match "^[\d\.]+$"  
81:  }  
82:    
83:  if ($searchType -like "all") {  
84:       returnAllRecords  
85:  }  
86:  elseif ($searchType -like "title") {  
87:       if (!$searchTerm) {  
88:            write-host "Search term required for search type: Title.`n"  
89:       }  
90:       else {  
91:            lookupByTitle -searchTermTitle $searchTerm  
92:       }  
93:  }  
94:  elseif ($searchType -like "category") {  
95:       if (!$searchTerm) {  
96:            write-host "Search term required for search type: Category.`n"  
97:       }  
98:       else {  
99:            lookupByCategory -searchTermCategory $searchTerm  
100:       }  
101:  }  
102:  elseif ($searchType -like "record") {  
103:       if (!$searchTerm) {  
104:            write-host "Search term required for search type: Record.`n"  
105:       }  
106:       else {  
107:            lookupByRecord -searchTermRecord $searchTerm  
108:       }  
109:  }  
110:  else {  
111:       write-host "Invalid search type.`n"  
112:  }  
113:    


Lastly, for good measure, some screenshots:





2014-06-27

Ups and Downs of moving house

An upside of moving house: lovely new view.



And a downside: boxes of stuff everywhere...


2014-06-11

Heading down the coast


I was uncharitably thinking it would be hard to take a nice shot of Ulladulla, but the harbor looks quite nice here:



By contrast, it was starting to look a little murky in Batemans Bay though:




2014-06-07

Mixed weather

Mixed weather over Killalea this morning; still damned pretty though.


2014-05-31

Bulk Extension Renamer - bash

As a quick counter-point to my earlier PowerShell script, here's my equivalent in bash:


1:  #!/bin/bash  
2:    
3:  if [ $# -lt 2 ]; then  
4:      echo -e "\e[33mUsage: $0 <current extension> <new extension>\e[0m"  
5:      exit 1  
6:  fi  
7:    
8:  for fileName in *.$1; do  
9:      newFileName=${fileName/.$1/.$2}  
10:      if [ -f "$newFileName" ]; then  
11:          echo -e "\e[31mNot renaming \e[1m$fileName\e[22m to \e[1m$newFileName\e[22m -- File exists."  
12:      elif [ -d "$newFileName" ]; then  
13:          echo -e "\e[31mNot renaming \e[1m$fileName\e[22m to \e[1m$newFileName\e[22m -- Is a directory."  
14:      else  
15:                 if [ -w "$fileName" ]; then  
16:                      mv "$fileName" "$newFileName"  
17:                       echo -e "\e[1;32m$fileName\e[22m renamed to \e[1m$newFileName\e[0m"  
18:                 else  
19:                      echo -e "\e[31mUnable to rename \e[1m$fileName\e[22m - file is not writable\e[0m"  
20:                 fi  
21:      fi  
22:  done  

Short, neat and to the point. The only slightly unwieldy part is the rather ugly ANSI color codes.

As for functionality, it checks if the file already exists (or a directory with the same name exists) and throws an error if so. It also tests if the original file is writable before attempting to move it and errors out if it isn't.

Here it is running:
 

Change the ComputerName value in Unattend.xml using PowerShell

A quick and dirty PowerShell script to update the value of ComputerName in Unattend.xml before imaging.

This particular value is located at:

<unattend>
 <settings pass="generalize">
  <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <computername>

Which is a bit of a mouthful, but we can be lazy and just pull the value from the nth component node (in my case it's 3, or the 4th component node). PowerShell uses dots to describe the hierarchical path, which looks a lot neater than the above:

$xml.unattend.settings.component[3].computername


To repeat, the value of .component[n] will change depending on the structure of the file.

The value of the computername node can be changed by just providing the new value:

$xml.unattend.settings.component[3].computername = "$computerName"


The imported XML then needs to be saved back to the file on disk:

$xml.save("$unattendFile")


1:  param(  
2:       [parameter(Mandatory = $true)]  
3:       [ValidateNotNullOrEmpty()]  
4:       [string]$computerName  
5:  )  
6:    
7:  Set-ExecutionPolicy Unrestricted  
8:    
9:  $systemDrive = $env:systemdrive  
10:  $unattendFile = "$systemDrive\Unattend.xml"  
11:    
12:  [xml]$xml = get-content $unattendFile  
13:    
14:  $currentName = $xml.unattend.settings.component[3].computername  
15:  write-host "Current Name: "$currentName"`n"  
16:    
17:  $xml.unattend.settings.component[3].computername = "$computerName"  
18:    
19:  $newName = $xml.unattend.settings.component[3].computername  
20:  write-host "New Name: "$newName"`n"  
21:    
22:  $xml.save("$unattendFile")  

Customized Windows PE 5.0

A quick run-through covering creating a customized Windows PE bootable drive, mainly so I don't space out and forget any of the steps (*ahem* again).

The below is based on the Deployment and Imaging tools available by installing Windows ADK 8.1


Create Windows PE files

Run Deployment and Imaging Tools Environment as Administrator

Create the base structure with copype command:

copype <architecture> <directory>

Example for 64 bit:
copype amd64 c:\winpe64

Example for 32 bit:
copype x86 c:\winpe32


Paths to packages

amd64:
\Program Files (x86)\Windows Kits\8.1\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs


x86:
\Program Files (x86)\Windows Kits\8.1\Assessment and Deployment Kit\Windows Preinstallation Environment\x86\WinPE_OCs



Mount boot.wim

(assuming current path is the root of WinPE, e.g., c:\winpe)

dism /mount-wim /wimfile:media\sources\boot.wim /index:1 /mountdir:mount




Adding Key Packages

(assuming current path is \Program Files (x86)\Windows Kits\8.1\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs)


1:  dism /image:c:\winpe\mount /add-package /packagepath:WinPE-Scripting.cab  
2:  dism /image:c:\winpe\mount /add-package /packagepath:en-us\WinPE-Scripting_en-us.cab  
3:    
4:  dism /image:c:\winpe\mount /add-package /packagepath:WinPE-WMI.cab  
5:  dism /image:c:\winpe\mount /add-package /packagepath:en-us\WinPE-WMI_en-us.cab  
6:    
7:  dism /image:c:\winpe\mount /add-package /packagepath:WinPE-MDAC.cab  
8:  dism /image:c:\winpe\mount /add-package /packagepath:en-us\WinPE-MDAC_en-us.cab  
9:    
10:  dism /image:c:\winpe\mount /add-package /packagepath:WinPE-HTA.cab  
11:  dism /image:c:\winpe\mount /add-package /packagepath:en-us\WinPE-HTA_en-us.cab  
12:    
13:  dism /image:c:\winpe\mount /add-package /packagepath:WinPE-NetFx.cab  
14:  dism /image:c:\winpe\mount /add-package /packagepath:en-us\WinPE-NetFx_en-us.cab  
15:    
16:  dism /image:c:\winpe\mount /add-package /packagepath:WinPE-PowerShell.cab  
17:  dism /image:c:\winpe\mount /add-package /packagepath:en-us\WinPE-PowerShell_en-us.cab  
18:    
19:  dism /image:c:\winpe\mount /add-package /packagepath:WinPE-DismCmdlets.cab  
20:  dism /image:c:\winpe\mount /add-package /packagepath:en-us\WinPE-DismCmdlets_en-us.cab  


Add customizations

Add a customized HTA menu (e.g., menu.hta in \windows\hta\) then add the below line to startnet.cmd in \windows\system32 to open it on startup:

%windir%\system32\mshta.exe %windir%\hta\menu.hta




Unmount boot.wim after committing changes

dism /unmount-wim /mountdir:c:\winpe\mount /commit


Prepare USB stick

(via either diskpart or Disk Management. The partition must be marked as Active.)

diskpart
list disk
select <disk number>
clean
create partition primary
format quick fs=ntfs label="WinPE"
assign letter=W
active


Example for finding the correct Disk number:

DISKPART> list disk

  Disk ###  Status         Size     Free     Dyn  Gpt
  --------  -------------  -------  -------  ---  ---
  Disk 0    Online          465 GB      0 B
  Disk 1    Online         7634 MB      0 B

DISKPART> sel disk 1

Disk 1 is now the selected disk.


Alternatively, prepare a USB HDD with multiple partitions:


diskpart
list disk
select <disk number>
clean
create partition primary
format quick fs=ntfs label="WinPE"
assign letter=W
active
select <disk number>
clean
create partition primary
format quick fs=ntfs label="Data"
assign letter=X


It's worth noting that UEFI only supports booting from FAT32 partitions.


Copy \media\ and its sub-directories to the root of the USB stick/drive:

robocopy /mir c:\winpe\media w:


Bulk File Extension Renamer - PowerShell

Here's a quick PowerShell script to change the extension on a group of matching files, posted chiefly to illustrate how much more concise PowerShell can be when compared to VBScript (I'll post an equivalent script shortly). The script below is still about twice the length of the a similar script I wrote in bash for *nix but it's certainly an improvement in both length and readability over VBS.

First up, grab the required parameters (old extension, new extension) from the command line. If either or both are missing, the user will be prompted to enter them.

Each parameter is set with three options -


[parameter(Mandatory = $true)] makes the parameter mandator.

ValidateNotNullorEmpty is called to do exactly what it says on the tin.
 

[string]$oldExt puts the value of the parameter into a string called $oldExt.

1:  param(  
2:       [parameter(Mandatory = $true)]  
3:       [ValidateNotNullOrEmpty()]  
4:       [string]$oldExt,  
5:       [parameter(Mandatory = $true)]  
6:       [ValidateNotNullOrEmpty()]  
7:       [string]$newExt  
8:  )
9:

Use Get-ChildItem to fill an array with files that have the old extension.

10:  $files = @(Get-ChildItem *.$oldExt)

If there is at least one filename in the array, loop through the array. Otherwise let the user know that there were no matches.

11:  if ($files.length -gt 0){
12:       foreach($file in $files){
13:              write-host "`nCurrent Name:" $file.Name
[ ... ]
32:  else {  
33:       write-host "No files with extension:" $oldExt`n -foregroundcolor "yellow"  
34:  }  


Create the new filename by combining the BaseName (original file sans extension) with the new extension (joined with a dot).

15:            $newName = $file.BaseName + "." + $newExt  
16:            write-host "New Name:" $newName  

Check if a file or directory with the new name already exists. Throw an error if so (in red, because *alarming*).
17:            if (Test-Path $newName) {  
18:                 write-host "Error: Can't rename" $file.Name "to" $newName "- a file with that name already exists`n" -foregroundcolor "red"  
19:            }  
20:            elseif ($file.Attributes -like "*ReadOnly*") {  
21:                 write-host "Cannot rename" $file.Name "- file is Read Only`n" -foregroundcolor "red"  
22:            }  
23:            elseif ($file.Attributes -like "*Directory*") {  
24:                 write-host "Not renaming" $file.Name "- it is a directory`n" -foregroundcolor "red"  
25:            } 

Otherwise rename the file and confirm with a happier green message.

26:            else {  
27:                 rename-item -path $file.Name -newname $newName  
28:                 write-host "File renamed`n" -foregroundcolor "green"  
29:            }  

And that's about that. Here's a screenshot of it in action:



Finally, for good measure, here's the complete listing:
1:  param(  
2:       [parameter(Mandatory = $true)]  
3:       [ValidateNotNullOrEmpty()]  
4:       [string]$oldExt,  
5:       [parameter(Mandatory = $true)]  
6:       [ValidateNotNullOrEmpty()]  
7:       [string]$newExt  
8:  )  
9:    
10:  $files = @(Get-ChildItem *.$oldExt)  
11:  if ($files.length -gt 0) {  
12:       write-host "`nFiles to be processed:" $files.length -foregroundcolor "yellow"  
13:       foreach($file in $files) {  
14:            write-host "`nCurrent Name:" $file.Name  
15:            $newName = $file.BaseName + "." + $newExt  
16:            write-host "New Name:" $newName  
17:            if (Test-Path $newName) {  
18:                 write-host "Error: Can't rename" $file.Name "to" $newName "- a file with that name already exists`n" -foregroundcolor "red"  
19:            }  
20:            elseif ($file.Attributes -like "*ReadOnly*") {  
21:                 write-host "Cannot rename" $file.Name "- file is Read Only`n" -foregroundcolor "red"  
22:            }  
23:            elseif ($file.Attributes -like "*Directory*") {  
24:                 write-host "Not renaming" $file.Name "- it is a directory`n" -foregroundcolor "red"  
25:            }  
26:            else {  
27:                 rename-item -path $file.Name -newname $newName  
28:                 write-host "File renamed`n" -foregroundcolor "green"  
29:            }  
30:       }  
31:  }  
32:  else {  
33:       write-host "No files with extension:" $oldExt`n -foregroundcolor "yellow"  
34:  }  

2014-05-08

Not a bad background for a morning


The view from my overnight digs made a very pleasant background for breakfast/coffee o'clock this morning. Loved the silence most of all - buried in the bush between Tathra and Bega.







Not that the interior was anything to sneeze at...




You just have to love off-peak rates that make places like this affordable for a simple business trip :)

Quote for the day

"I have so little that is fanciful or poetical about my own individu [sic] that I must trick out my dwelling with something fantastical otherwise the Coerulean Nymphs and swains will hold me nothing worth."

- Sir Walter Scott

2014-03-23

Photos from Game 2 of the MLB 2014 Opening Series at the SCG


The seats were pretty good - in the shade, gave a decent overview of the game and provided a great side-on view of the homer in the bottom of the 9th.





2014-03-08

Sydney Derby 2014-03-08: 3-1 to the Boys in Blue!

Assembling for the march to the ground.

In fine voice as usual. Awesome to see a giant throng of Sky Blue marching down Foveaux Street!

At the ground, not long after kickoff. This was the closest thing to an in-focus shot I took inside the stadium. Far too much excitement going on in the Cove to be constantly pulling out the phone anyway.

2014-03-01

Photos from away trip - Sydney FC @ CC Mariners - 2014-03-01

Flying sauce bottle? Sure, why not...

Warming up next to the bloody sauce bottles.

The traveling Cove; with the Brisbane Water in the background

The sparsely populated home end. They did have a brass section though.