Tuesday, May 29, 2012

OpenBox Key Bindings

I've been using Arch Linux on my test box for the last few months and I really like it. I still feel like a linux noob, and they say that Arch isn't for noobs, but I felt that the set up was pretty straight forward. Arch installs as bare boned as possible, with no gui. So I installed and configured X and then installed OpenBox as a windows manager. And that's it. No login manager, no task bar, no conky, no file manager, nada.

OpenBox comes with a configurable start menu that you can reach by right-clicking on the desktop. You can also configure keybindings by editing your ~/.config/openbox/rc.xml file. I was really missing the window positioning keyboard short cuts that come with windows that allow you to maximize a window or split the screen with a window.  So I added them to my rc.xml file, and then I added a few more that I wished windows would have come with.  My screen resolution on that machine is 1200x1600, so the window heights and widths are based on that.  Here's a snippet of my config file:


<!-- Keybindings for moving windows --> 
<!-- In the key attribute, the W refers to the 
     windows/super key, C refers to the ctrl key and KP_# refers
     to a number on the numpad. -->
<!-- Move and resize the window to fill the top left quarter of the screen --> <keybind key="W-C-KP_7">
  <action name="UnmaximizeFull" />
  <action name="MoveResizeTo">
    <height>600</height>
    <width>800</widht>
    <x>0</x>
    <y>0</y>
  </action>
</keybind>

<!-- Move and resize the window to fill the top right quarter of the screen --> <keybind key="W-C-KP_9">
  <action name="UnmaximizeFull" />
  <action name="MoveResizeTo">
    <height>600</height>
    <width>800</widht>
    <x>800</x>
    <y>0</y>
  </action>
</keybind>

<!-- Move and resize the window to fill the bottom left quarter of the screen --> 
<keybind key="W-C-KP_1">
  <action name="UnmaximizeFull" />
  <action name="MoveResizeTo">
    <height>600</height>
    <width>800</widht>
    <x>0</x>
    <y>600</y>
  </action>
</keybind>

<!-- Move and resize the window to fill the bottom right quarter of the screen --> 
<keybind key="W-C-KP_3">
  <action name="UnmaximizeFull" />
  <action name="MoveResizeTo">
    <height>600</height>
    <width>800</widht>
    <x>800</x>
    <y>600</y>
  </action>
</keybind>

<!-- Move and resize the window to fill the top half of the screen --> 
<keybind key="W-C-KP_8">
  <action name="UnmaximizeFull" />
  <action name="MaximizeHorz" />
  <action name="MoveResizeTo">
    <height>600</height>
    <x>0</x>
    <y>0</y>
  </action>
</keybind>

<!-- Move and resize the window to fill the right half of the screen --> 
<keybind key="W-C-KP_6">
  <action name="UnmaximizeFull" />
  <action name="MaximizeVert" />
  <action name="MoveResizeTo">
    <width>800</width>
    <x>800</x>
    <y>0</y>
  </action>
</keybind>
<!-- Move and resize the window to fill the bottom half of the screen --> 
<keybind key="W-C-KP_2">
  <action name="UnmaximizeFull" />
  <action name="MaximizeHorz" />
  <action name="MoveResizeTo">
    <height>600</height>
    <x>0</x>
    <y>600</y>
  </action>
</keybind>

<!-- Move and resize the window to fill the right half of the screen --> 
<keybind key="W-C-KP_4">
  <action name="UnmaximizeFull" />
  <action name="MaximizeVert" />
  <action name="MoveResizeTo">
    <width>800</width>
    <x>0</x>
    <y>0</y>
  </action>
</keybind>
<!-- Resize and center the window --> 
<keybind key="W-C-KP_5">
  <action name="UnmaximizeFull" />
  <action name="MoveResizeTo">
    <height>600</height>
    <width>800</widht>
    <x>400</x>
    <y>300</y>
  </action>
</keybind>







Wednesday, May 02, 2012

CSS vertical-align Property

I had an issue where I needed to vertically align a label to the top of a textarea. Here's the sample html:

<p>
    <label for="txtDesc">Description</label>
    <textarea id="txtDesc"></textarea>
</p>

Here's what it looked like:

My first inclination was to put a "vertical-align: top" css rule on the label to raise it up to the "top" of the text area. However, that didn't work.

The trick was to use the rule on the text area instead. Here's that same code with "vertical-align: top;" applied to the textarea:

Friday, February 06, 2009

Project Euler - Problem 3

Problem 3 reads as follows:

"The prime factors of 13195 are 5, 7, 13 and 29.

What is the largest prime factor of the number 600851475143 ?"


This one is easy, thanks to Ruby's mathn library and the prime_division method. You can read more about it and even see the source code for the method at the documentation site.

All we have to do is require the mathn library, which comes with Ruby by default. I checked on my Windows and Mac OSX machines. Then call the prime_division method on the integer. That creates a multidimensional array.

For each item in the array, there are 2 numbers. The first is the actual prime number and the second relates how many times that prime number can be factored out. So, for the number 9, you would end up with [3,2].

Lastly, we grab the last prime number in the array for the answer.

require 'mathn'
primeArray = 600851475143.prime_division
puts primeArray[primeArray.length - 1][0]

Monday, February 02, 2009

Calling XSLT templates with predicates..

This is just a mental note for me, so hopefully I won't forget it in the future.

If you have an XSLT template that limits the result set with a predicate, you must call that template with the predicate intact. Here's an example:

Wrong:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="Items">
<xsl:apply-templates select="Item" />
</xsl:template>

<xsl:template match="Item[status='archived']">
<xsl:element name="title">
<xsl:value-of select="title" />
</xsl:element>
</xsl:template>

</xsl:stylesheet>


Right:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="Items">
<xsl:apply-templates select="Item[status='archived']" />
</xsl:template>

<xsl:template match="Item[status='archived']">
<xsl:element name="title">
<xsl:value-of select="title" />
</xsl:element>
</xsl:template>

</xsl:stylesheet>


I am ashamed at how long it took me to figure out what I was doing wrong. ;)

Friday, January 30, 2009

Project Euler - Problem 2

Alright, on to problem 2. "Find the sum of all the even-valued terms in the [Fibonacci] sequence which do not exceed four million." This one is pretty easy. Just loop through all the numbers in the Fibonacci sequence up to four million. The largest actual number in the sequence that does not exceed 4 million is 3,524,578. Here's is my humble attempt at a solution:

x1,x2 = 0, 1
ans = 0

# While x1 is less than or equal to 4 million
while(x1 <= 4000000)

# Find the next number in the Fibonacci sequence
x1+=x2
x1,x2= x2,x1

# If that number is even, then add it to the running sum.
if(x1%2 == 0) then ans += x1 end
end

puts ans

Tuesday, January 27, 2009

Ruby FTP Scanner

I was recently given the task to recursively scan an ftp directory and generate a list of all the files in all the folders in that directory. Here's a little ruby script that I wrote to accomplish the scan.

require 'net/ftp'

# The scanDir function searches through the directory that is passed in as an argument. If that directory has any sub directories,
# then the function calls itself to handle them.
def scanDir(ftp, dir)

ftp.chdir(dir)
puts ftp.pwd + "/."

entries = ftp.list('*')

entries.each do |entry|

if entry.split[2] == "<dir>" then
# If this is a directory then call scanDir to scan it.
scanDir(ftp, entry.split.last)
else
# else, print out the name of the file.
puts ftp.pwd + "/" + entry.split.last
end

end

# Since we dipped down a level to scan this directory, lets go back to the parent so we can scan the next directory.
ftp.chdir('..')
end

# Determine if the user is asking for help.
helpArgs = ["h", "-h", "/h", "?", "-?", "/?"]
if helpArgs.index(ARGV[0]) != nil || ARGV.length == 0 then

puts "FTPSCAN:"
puts " The ftpscan script recursively scans an ftp directory and returns a list of all the files and directories contained therein."
puts
puts " USAGE:"
puts " ruby ftpscan.rb [ftpserver] [username] [password]"
puts
puts " EXAMPLE:"
puts " ruby ftpscan.rb tsftp.turner.com steveo stevepass"
puts

else

# Get the command line arguments
server, user, pass = ARGV

# Connect to the FTP Server
ftp = Net::FTP.new(server)

# Login to the FTP account
ftp.login(user, pass)

# Recursively scan the directories.
scanDir(ftp, '')

# Close the FTP connection.
ftp.close

end


Enjoy!

Friday, January 23, 2009

Project Euler - Problem 1

I found a great site called Project Euler. The site explains it best:

"Project Euler is a series of challenging mathematical/computer programming problems that will require more than just mathematical insights to solve. Although mathematics will help you arrive at elegant and efficient methods, the use of a computer and programming skills will be required to solve most problems.

The motivation for starting Project Euler, and its continuation, is to provide a platform for the inquiring mind to delve into unfamiliar areas and learn new concepts in a fun and recreational context."

I've been using Ruby as an alternative to PowerShell, since it runs on the miriad of systems that I am exposed to in my current position. I figured that this would be a good way to increase my Ruby coding skills and have a little fun solving some puzzles at the same time. From time to time, I'll post my solution to a problem. I'm still learning, so if you have suggestions, I would love to hear your constructive criticism.

Problem 1:
Find the sum of all the multiples of 3 or 5 below 1000.

Solution:

ans=0

(1...1000).each{ |i|
  if( i%3 == 0 || i%5 == 0 ) then
    ans += i
  end
}

puts ans


I doesn't seem very "Ruby-ish" but it works.

Monday, July 28, 2008

Ruby cp_r caveat

The ruby fileutil function cp_r, copies a directory, all of its files and subdirectories to a target location.  This is very useful when you are trying to sync 2 directories.  However, by default it will copy the directory as a subdirectory of the supplied target directory.  So:

cp_r "c:\\fly", "c:\\soup"

would give you:

"c:\\soup\\fly"

Now you have a fly in your soup.  This is a serious problem.  What if you were trying to sync your stick and donkey folders?

To get around this, just stick a period at the end of the the original directory path.  Like so:

cr_r "c:\\fly\\.", "c:\\soup"

Friday, July 18, 2008

A tale of two documentations

From time to time I find myself needing to integrate our system with some external vendor, and that usually means writing an XSL transform.  Last week I had 2 completely different experiences dealing with documentation from a couple of vendors.  Let's compare, shall we?

Company #1:

Company #1 is a large internet video distribution company, which "empowers content owners... to reach their audiences directly through the internet."  And they are very good at what they do.  They have probably fed you a video through some web site and you don't even know it.  So when it came time to generate an xslt to integrate with their system, I sat down and read the 4 separate documents that describe how to generate the xml manifest.  For the next few days, I played email tag with their support team as I fixed one issue only to unveil another.  It turned out that their documentation had a few errors.  You know, little things like incorrect tag names, required fields that weren't specified as required, and the fact that their xml parser is case sensitive.   That last one really steamed me.  I have since used the documentation as firewood to fend off the chill that came over me after excluding a distribution region by using a tag named "allow" (no attributes on this tag).

Company #2:

On the opposite end of the spectrum is company #2.  Its a small, very specialized, service provider with a single developer currently dedicated to this particular project.  Instead of getting a word or pdf document describing the xml creation process, I was given a highly commented DTD document.  And, surprise, this integration worked the first time without errors. 

I've conversed with several of my colleagues about this and most of them fail to see the awesomeness of this approach.  So, for those of you who missed it, here's why it is so awesome.  Not only was the documentation completely correct, it couldn't have been incorrect.  By passing me their DTD, they were saying "Here is the code that we use to validate your response.  If it validates for you, it will validate for us as well."  In this instance the code itself was enough.  They didn't even have to send an example xml file.  XmlSpy generated one in less than a second. 

I also feel that the comments left directly in the code, in this case the DTD, are a much clearer reflection of the author's intent.  This is the author spilling out his thought process, not just some dud that's been told to document a process by Friday. 

This experience just validates my belief that large external documents are slowly going the way of the dodo.  I've felt this way for a while now.  I'm a big fan of less documentation that is more useful.  Think about it.  End user's don't want to read a manual anymore.  They've come to expect inline help and most are even trained to look for tooltips. 

Song of the day:
State of the Union - David Ford - I Sincerely Apologize for All the Trouble I've Caused

Thursday, July 17, 2008

Uppercase in XSLT

XPATH doesn't have a built in ToUpper() or ToLower() function.  However, you can use the translate function to switch cases.  Here's an example that changes the word "Upper" to all upper case.

<xsl:variable name="text" select="'Upper'" />
<xsl:value-of select="translate($text, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />

If you want to go the other way and lowercase your string, just flip-flop the alphabet strings.

<xsl:variable name="text" select="'Upper'" />
<xsl:value-of select="translate($text, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'" />

Song of the day:
Twilight Zone(Live) - Golden Earring - The Naked Truth

Tuesday, July 15, 2008

Subversion Video

I came across this getting started with subversion video by Dan Wahlin. It's pretty good and would have saved me hours if I had know about it when I got started.  Dan does a good job explaining some of subversion's quirks and how to get around them.

http://weblogs.asp.net/dwahlin/archive/2007/08/13/video-how-to-getting-started-with-subversion-and-source-control.aspx

Song of the day:
Africa(Toto Cover) - Pyogenesis - Mono... or Will It Ever Be The Way It Used To Be

Monday, July 14, 2008

C# Succ

I have a project which requires me to generate multiple artifacts with sequential names.  No sweat, right?  Just stick a number on the end of the name and increment it.  Well, what if your users prefer letters to numbers? 

Ruby's string.succ function returns the successor to the string by incrementing characters starting from the rightmost alphanumeric character.  It's a shame that C# doesn't have this built in. 

Here's my stab at recreating the Ruby succ function in C#.  It's not as robust as the ruby version, as it only handles letters, but it is a start and it meets my needs for now.

public static string Succ(string value)
{
List<string> alphabet = new List<string>(" ,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z".Split(",".ToCharArray()));
char[] values = (" " + value).ToUpper().ToCharArray();
bool addone = true;

for(int i = values.Length - 1; i > -1; i--)
{
if (addone)
{
if (values[i] != 'Z')
{
values[i] = char.Parse(alphabet[alphabet.IndexOf(values[i].ToString()) + 1]);
addone = false;
}
else
values[i] = 'A';
}
}

return new string(values).Trim();
}


Here's some sample output:


  • Succ("R") => "S"

  • Succ("Z") => "AA"

  • Succ("ZAZ") => "ZBA"





Song of the day:

A Moment of Clarity - Therapy? - Infernal Love



Friday, May 30, 2008

A Million Lines of Code

I went to a product demo the other day for a CMS that is being developed in house.  I guess they want everybody to start using it.  The presenter went on an on about how flexible it was and how it could do anything.  It can scramble your eggs as long as you can pass in the eggs in a parseable format.  Apparently, they started development in back in 2000 and now it's ready for prime time.  That's right pasters, 8 years ago. 

Anyway, things were going along great, when something the presenter said hit me like a ton of bricks.  "This [application] has over a million lines of code."  Now, what would your reaction be if someone told you that their application had a million lines of code?  I had two.

1.  What does that even mean?

It seems silly to even mention this type of metric.  Are they still getting paid by the number of lines they produce?  I assume he was trying to impress the more non-technical folks in the room who now think that this thing is approaching the same level as the space shuttle.  (The avionics system, the code that flies the shuttle, has roughly 2 million lines of code.)  But to me it sounds like bloat, which lead me to my next reaction.

2. I bet I could write that in 999,999 lines of code.

You would think that in a million lines of code, there'd be a good refactor somewhere.  I would have expected them to find it by at least the sixth year.

The million lines of code also scream, "This is really complex and when it breaks, boy is it going to break."  Simplicity, that gets the job done, beats complexity any day.  Simplicity breeds confidence and attracts users.  I've added it to my developer's ethos.

Thursday, March 06, 2008

Replace Visual Studio Command Prompt with Powershell

I've been using sqlmetal a lot lately.  The easiest way to use it is through the Visual Studio Command Prompt.  In my case, I'm using the Visual Studio 2008(9.0) command prompt.  The PowerShell lover in me hated the fact that I had to go to another shell to do this.  After a brief inquiry, the all great Google led me to this excellent post by Robert Anderson which explains how to edit your PowerShell profile to correctly set all the environment variables used by the Visual Studio 2005 command prompt.  I've made a few tweaks for Visual Studio 2008 and am re-posting it for your enjoyment.

Just add the code below to your profile.

#Set environment variables for Visual Studio Command Prompt
pushd 'C:\Program Files\Microsoft Visual Studio 9.0\vc'
cmd /c “vcvarsall.bat&set” |
foreach {
if ($_ -match “=”) {
$v = $_.split(“=”); set-item -force -path "ENV:\$($v[0])" -value "$($v[1])"
}
}
popd
write-host "`nVisual Studio 2008 Command Prompt variables set." -ForegroundColor Yellow

Tweak Vista's Search Index

I'm not sure how I did anything on XP before I started using app launchers.  My first was Colibri, but then I found my true love, Launchy.  It's so liberating not to have to click the start menu(press ctrl+esc or win key), then find programs(press p) and then search through a gigantic list of stuff for what you want.  With Launchy, you just hit your short cut key and start typing in what you want. 

Vista's start menu comes with a similar search box that let's you type in what you want.  I think that they threw this in because actually going to Programs and looking for what you want is a hideous experience in Vista.  I keep all my applications that don't require an installation in a separate folder named "Programs".  Vista doesn't search this folder by default, so I had to modify the settings for the start menu... no, no... that's not it.  Maybe it's the user preferences... no, that's not it either.  Oh there it is, in the indexing service.

In the Vista search box type "index" and it should find "Indexing Options".  Inside Indexing Options click the Modify button to specify which folders to index.  I actually turned off a few that I didn't care about.  Things like other user's folders, and Outlook.  You can actually disable the service all together if you want to get a slight performance boost, but I like the search bar too much to kill it. 

For those of you who are keyboard bound like me, might I also suggest using SlimKeys in conjunction with the Vista search.  SlimKeys comes with an app launcher, but I disabled it.  I am using it's hotkey manager, window positioner/sizer, volume controller, screen grabber and it's format removing paster.  I highly recommend checking it out just for the window positioner/sizer.  It's great to be able to move a window to any corner, or center it or maximize it and even move it to my other monitor with a single keystroke.

Tuesday, March 04, 2008

Isilon Training: Day Two

Today we went through a lot of demos and labs.  The most impressive was the "Upgrade" demo.  We had a test cluster that was a version behind.  The instructor dropped a tar file on one of the nodes, ran an upgrade command from the command line and a couple of minutes later... BAM!  All three nodes in the cluster were updated with no down time.  The only instance where the nodes would have to be rebooted is when there is a change to the kernel.  They have a service that migrates the change to the other nodes so you don't have to. 

All in all it was really cool and I can't wait to get to play with ours.  If they give me access. :)

Isilon Training: Day One

I spent yesterday in a training class for the Isilon system that we use at work.  Isilon offers a clustered storage solution that is quite impressive both in its performance and its implementation.  I know that you can go the web site and look at all the specs, but I thought I would take some time and share the things that jumped out at me during the first day of training.

First off, I experienced a slight culture shock when they started talking about capacities.  Speaking from a developer's perspective, I'm used to talking Megabytes when referring to my applications and possibly Gigabytes when talking about data storage.  These guys talk Terabytes and Petabytes.  Imagine what you could do with a petabyte of code.  I think Skynet became self aware right around 1.3 petabytes.

Now as you can imagine its pretty hard to manage that much data.  The mainstream file systems just won't cut it, so they wrote their own.  They based their OneFS file system and OS on FreeBSD.  Each node in the cluster runs the OS and communicates with the other nodes so that each node knows what the other nodes have and are doing.  This way, there isn't a single controller unit.  Any node could go down completely and the system will continue to run without a hiccup.  It also makes it easier to add expansion nodes.  You can easily add several terabytes of new storage to the system in approximately 60 seconds.

One of the coolest decisions that they made was to stripe files across nodes and not across disks(most nodes have 12 disks).  This provides the highest level of data protection in the event of a failure. 

In today's class, we'll be looking at some troubleshooting exercises and hands on labs.  Should be fun.

Friday, February 29, 2008

Tweaking the SiteMap Navigation Menu

I have a site that uses a SiteMap provider and a Menu control for the site's navigation controls. Using the SiteMap provider is a simple and quick way to get dynamic menu for your site. Everything was going along smoothly until I was asked to have one of the menu items open it's link in a new window.

If this was just a link, I'd add a "target='_blank'" attribute and be done. However, a quick romp in the web.sitemap file showed that Visual Studio didn't have anything in the intellisence that resembled the target attribute. So what are we to do? Well, I'm glad you asked.

A little digging showed that the System.Web.UI.WebControls.MenuItem object actually had a target property. So all I had to do was set it. In the Web.Sitemap, I added a target attribute to the sitemap node.

<siteMapNode url="http://ewo/" title="EWO" target="_blank" />


Then I mapped the OnMenuItemDataBound event to a custom handler.



<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" ShowStartingNode="false" />
<asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1" Orientation="Horizontal"
OnMenuItemDataBound="Menu1_MenuItemDataBound">


The target attribute that I set in the SiteMapNode is translated into the dataobject and can easily be retrieved and used to set the MenuItem's target property.



protected void Menu1_MenuItemDataBound(object sender, MenuEventArgs e)
{
SiteMapNode node = (SiteMapNode)e.Item.DataItem;

if (node["target"] != null)
e.Item.Target = node["target"];
}


There are other great attributes that can be set this way, including the image url, text and tooltip properties. Have fun!

Thursday, February 28, 2008

PowerShell Convert CSV to SQL Insert Script

Recently, I've been handed a lot of Excel spreadsheets (and various other formats) and told to move the data into a SQL table.  You could do this with DTS if you have that kind of access to the server, but suppose you didn't.  Here's a little PowerShell script that crunches through the rows in a CSV file and generates insert statements in a SQL script.  The script requires that you pass a path to the CSV file and also accepts an optional parameter for the name of the table to insert into.  If you don't pass this in, the filename is used as the table name.  The script is intentionally lengthy and properly commented to make it easier to read and understand. Here you go...

# Verify that a file argument was passed in.
if ($args[0]) { $file = $args[0] }
else { write-warning "You must supply a path to the csv."; break }

# Verify that the file exists.
if(![System.IO.File]::Exists($file)) { write-warning "Can not find '$file'."; break }

# Verify that the file is a csv file.
if(!$file.ToLower().EndsWith("csv")) { write-warning "The file specified is not a CSV file."; break }

# If no table name was provided, we'll use the file name instead.
if($args[1]) { $tableName = $args[1] }
else { ls $file | % { $tableName = $_.Name.ToLower().TrimEnd(".csv") } }

# Generate an informative header for the sql file.
# Note that the out-file command will overwrite any existing file.

$output = $file.ToLower().TrimEnd(".csv") + ".sql"
"/************************************************************`n" +
"** Script generated by CsvToBatchInsert.ps1 `n" +
"** Date: " + [System.DateTime]::Now.ToString("MM/dd/yyyy hh:mm:ss") + " `n" +
"** From file: $file `n" +
"************************************************************/`n" | out-file -filepath $output

# Loop through the rows in the csv file.
Import-Csv $file | % {
# The insert variable is used to build a single insert statement.
$insert = "INSERT INTO $tableName ("

# We only care about the noteproperties, no use dealing with methods and the such.
$properties = $_ | Get-Member | where { $_.MemberType -eq "NoteProperty" }

# Create a comma delimited string of all the property names to use in the insert statement.
# You should make sure that the column headings in the CSV file match the field names in
# your table before you run the script.

$properties | % { $insert += $_.Name + ", " }

$insert = $insert.TrimEnd(", ") + ") VALUES ("

# Couldn't figure out how to access the value directly. So here I'm forced to use
# substring to get it. The Definition looks like "System.String PropertyName=PropertyValue".
# Since the value will be enclosed in single quotes, you will run into trouble if the value
# contains a single quote. To escape the single quote in T-SQL, just put another single quote
# directly in front of it.

$properties | % {
$value = $_.Definition.SubString($_.Definition.IndexOf("=") + 1)
$insert += "'" + $value.Replace("'", "''") + "', "
}

$insert = $insert.TrimEnd(", ") + ")"

# Append the insert statement to the end of the output file.
$insert | out-file -filepath $output -append
}


You can easily tweak this script to generate update statements, or delete statements, or anything else for that matter.  As always, I welcome any comments, especially ones that show a better way of doing this.  Enjoy!!!

Tuesday, February 26, 2008

Dynamically create Powershell objects

I wrote a sweet powershell script today that dynamically generated a custom object.  To create an object in Powershell, you basically edit an existing object by adding new methods and properties.  In my case, I used System.Object and added some properties. 

Suppose you are in the middle of a powershell script and you realize that you need a cat class.  Cat's have claws, fur and multiple output devices, but let's limit ourselves to just one.

$myCat = New-Object -TypeName System.Object
$myCat | Add-Member -MemberType noteProperty -Name "Fur" -Value "Soft"
$myCat | Add-Member -MemberType noteProperty -Name "Claws" -Value "Sharp"
$myCat | Add-Member -MemberType ScriptMethod GenerateHairBall { $hairball = "Hmmph, hmmph, ack, aaaaaack! There you go!"; $hairball }

And there you go.  If you have more than one cat, you can store them in an array.  Like this:

$cardboardBox += $myCat
$cardboardBox += $SarahsCat

etc...