# Tuesday, September 09, 2008

I find myself doing this over and over again, so I figured it would be worthwhile to post.  Below you’ll find a really useful way for installing a Windows O/S from a bootable USB device.  I am particularly dependent on USB drives, as I have a Lenovo X61 Tablet that doesn’t have a CD/DVD-ROM (unless I’m docked, but I’m hardly in the office).

A couple of notes:

  • This assumes you’re running Windows Vista or Windows Server 2008
  • I’ve tested by installing the following O/S’s: Windows XP SP3, Windows Vista, and Windows Server 2008
  • You must have a machine capable of booting from a USB drive

Without further ado, here are the steps:

  1. Open an elevated command prompt.
  2. You must make your USB drive bootable.  Type the following in the command prompt:

    diskpart
    list disk (FIND YOUR USB DISK)
    select disk 1 (OR WHATEVER YOUR DISK NUMBER IS)
    clean
    create partition primary
    select partition 1
    active
    format fs=NTFS
    assign
    exit

  3. Mount your Windows Server ISO (or unpack it) and copy the contents of the CD/DVD onto your USB.  Make sure you get all files, including hidden ones.

You should now be able to use this USB drive to install a new O/S.  Good luck!

posted on Tuesday, September 09, 2008 3:23:57 PM (Central Standard Time, UTC-06:00)  #    Comments [0] Trackback
# Saturday, September 01, 2007

Lately it seems that I have had to acquire a lot of hotfixes for Microsoft products.  Unfortunately, most of the KB articles don't provide a link to the hotfix, but instead ask you to contact Microsoft Support (via phone) to acquire the hotfix.  Kind of a pain!

Fortunately, my friend Rich Finn just passed along this useful link:

Hotfix Request Web Submission Form

Very useful ... no longer will I have to reach out an contact individual escalation engineers I've worked with in the past. <sheepish grin>

posted on Saturday, September 01, 2007 10:07:47 AM (Central Standard Time, UTC-06:00)  #    Comments [1] Trackback
# Monday, August 13, 2007

I came across a frustrating interesting problem today where the BizTalk Server 2006 Configuration wizard would fail every time I applied a new configuration.

Unlike a typical BizTalk developer environment (which usually consists of BizTalk and SQL Server on the same machine), this environment consisted of two separate machines: one BizTalk Server 2006 and one SQL Server 2005 (i.e. the BizTalk databases are stored on the SQL Server).  Additionally, this is a virtual environment and both machines were cloned from the same base Windows Server 2003 R2 template.

I was installing the following components ...

  • Enterprise Single Sign-On (SSO)
  • Group
  • BizTalk Runtime
  • MSMQT

It would successfully install ENTSSO, but would fail when installing the group.  The log file reported the following error:

Failed to configure with error message [Exception of type 'System.EnterpriseServices.TransactionProxyException' was thrown.]

The following Google search suggested to me that  the underlying problem was with MSDTC (aren't all BizTalk problems?).  I checked, and double-checked, the MSDTC properties on both servers and couldn't find anything wrong with the configuration.  So, I had to pull out the big guns.

I downloaded DTCPing (a very handy tool for debugging DTC issues) and ran it on both machines (make sure to read the instructions on how to use DTCPing as it is not straightforward).  In the generated log file I noticed the following warning:

WARNING: the CID values for both test machines are the same while this problem won't stop DTCping test, MSDTC will fail for this ...

A Google search on this warning helped me to understand that the underlying problem is that the CID values stored for MSDTC were not changed during the cloning process.  But of course!

If you're experiencing this problem, check the following registry key on both of your machines.  Are the keys identical?

HKEY_CLASSES_ROOT\CID

Mine were.  Here's the steps I took successfully reinstall MSDTC so that the CID values were unique.  Run this procedure on both machines:

  1. Use Add Windows Components, and remove Network DTC.
  2. Go to the command line and run: MSDTC -uninstall
  3. Go to the registry and delete the MSDTC keys in HKLM/Software/Microsoft/Software/MSDTC, HKLM/System/CurrentControlSet/Services/MSDTC, and HKEY_CLASSES_ROOT\CID (if they're still there).
  4. Reboot
  5. Go to the command line and run: MSDTC -install
  6. Use Add Windows Components, and add Network DTC.
  7. Go to the command line and run: net start msdtc

After running this on both servers I was able to confirm that the CID values were unique.  And, sure enough, when I next applied my configuration to BizTalk Server 2006 everything worked perfectly.

I hope this helps!

posted on Monday, August 13, 2007 3:48:34 PM (Central Standard Time, UTC-06:00)  #    Comments [12] Trackback
# Saturday, July 28, 2007

I encountered an error today while setting up a project within the Commerce Server Staging.  I haven't encountered it before, which leads me to believe that I must have done something abnormal on my development virtual machine.

Commerce Server Staging (CSS) is a service that allows you to synchronize content and data between many separate environments. Utilizing CSS, you can reliably update both Web content and business data from the source to one or more destinations.

Using the CSS MMC, I created a simple project that stages my StarterSite content from my local directory (e.g. C:\Inetpub\wwwroot\StarterSite) to a temporary folder (e.g. C:\Temp\Destination).  It was meant to be the start of a proof-of-concept for a more complex network topology.  However, I almost immediately received an error when I attempted to start replication:

CSS: Unspecified Error

I just love errors like this!  Gives me something to research and figure out ...

Fortunately, more valuable information was added to the application log:

Event Type:    Error
Event Source:    Commerce Server Staging
Event Category:    None
Event ID:    61208
Computer:    CS2007
Description:
Error occurred with the database StagingLog.mdb.  Error is: System.Data.OleDb.OleDbException: Operation must use an updateable query.
   at System.Data.OleDb.OleDbCommand.ExecuteCommandTextForSingleResult(tagDBPARAMS dbParams, Object& executeResult)
   at System.Data.OleDb.OleDbCommand.ExecuteCommandText(Object& executeResult)
   at System.Data.OleDb.OleDbCommand.ExecuteCommand(CommandBehavior behavior, Object& executeResult)
   at System.Data.OleDb.OleDbCommand.ExecuteReaderInternal(CommandBehavior behavior, String method)
   at System.Data.OleDb.OleDbCommand.ExecuteNonQuery()
   at Microsoft.CommerceServer.Staging.Internal.ProjectDeploymentLog.ModifyLog(String projectName, String status).

While this isn't the most explicit error, it provided enough information to track down the problem.

You might be surprised to see that this error refers to an Access database.  CSS makes use of Access database files to store events and information it audits during the staging process.  Specifically, there are these two Access database files:

  • StagingLog.mdb
    • Found here: C:\Program Files\Microsoft Commerce Server 2007\Staging\Data
    • Stores internal replication information used by CSS
  • events.mdb
    • Found here: C:\Program Files\Microsoft Commerce Server 2007\Staging\Events
    • Stores staging information that is made available to reports

Searching on the keywords "mdb operation must use an updateable query" led me to KB article 175168.  This article indicated that the problem is most likely caused by a user not having the proper permissions to open the StagingLog.mdb file.

In comes File Monitor (aka FileMon), by SysInternals, to the rescue.  Seriously folks, save yourself the agony and get to know the tools available from Microsoft and SysInternals.

I was able to capture the following "Access Denied" message via File Monitor:

image

Solution: Turns out that the NT AUTHORITY\NETWORK SERVICE has been attempting to open the StagingLog.mdb file to no avail.  After giving the NT AUTHORITY\NETWORK SERVICE the rights to Modify the StagingLog.mdb file ...

image

... I am now able to successfully start my CSS project and stage my StarterSite data to a separate folder.

UPDATE: Rather than only giving access to the StagingLog.mdb file, give the NETWORK SERVICE account access to the entire Data folder where the MDB file is located.  Otherwise it will have issues trying to write out an LDF (Access log file) file when updates are made.

Hopefully this not only helps someone resolve this particular problem, but also shows how useful it is to equip yourself with good debugging tools!

Good luck!

posted on Saturday, July 28, 2007 2:37:35 PM (Central Standard Time, UTC-06:00)  #    Comments [1] Trackback
# Sunday, July 15, 2007

Years ago I made a serious mistake when I installed, and briefly used, iTunes -- I gave it the ability to reorganize my music folders!  Since then, all my nicely organized and sorted directories of (legally obtained) digital music have been disorganized and confused.

For example, I used to have a directory named "U2" where all my music for the group U2 was stored.  However, iTunes decided that my organization structure was too simple, and broke it out into folders derived from the contributing artists.  Now I have "Bono & The MDH Band", "Bono_Daniel Lanois", "Bono_Gavin Friday_Maurice Seezer", etc. It's a real mess.  Additionally, it left the folder "U2" with a bunch of empty subdirectories!  How rude!

I've made an effort, as of late, to try and clean-up this mess.  In doing so, I've ended up with a lot of empty directories that previously contained music and/or subdirectories.  After manually deleting a couple directories, I decided I needed to automate the process.  I was surprised to find that this process is not nearly as straightforward as I thought it would.

In going about this process, I decided to do the following:

  • Allow it to scan the directories first, and tell me which folders are empty (allows me to double-check!)
  • Ignore all hidden files (this is because Windows Media Player and iTunes create hidden album art which I don't want to preserve)
  • Log empty directories, deleted directories and errors
  • Scan first, delete second
  • Ignore read-only attributes (all my music is marked as read-only to prevent someone from doing what I'm doing)
  • Delete a directory if it is made empty because it's subdirectories are deleted

Let me break down how I accomplished these things.

To scan for empty directories, I created a method that starts with a predefined directory, and recursively iterates through all the subdirectories.  During this iteration, I scan the folder to see if it contains any files using the GetFiles method.  Rather than specify files with a specific file extension (like .mp3 or .wma) I decided to get all files by using the "*.*" pattern (directory happens to be DirectoryInfo object).

using System.IO;

...

FileInfo[] files;
files = directory.GetFiles("*.*");

However, many of the files are hidden (because WMP and iTunes creates album art that's hidden), so I decided to exclude hidden files.  I did this by checking the hidden attribute of the file, and if it was turned on I ignored the file.  If non-hidden files were found, I marked a local boolean value as true, indicating the folder contains files.

foreach (FileInfo file in files)
{
     // only look for files that are not marked as hidden
     if (!((file.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden))
     {
         notEmpty = true;
     }
}

Next, I want to check to see if the directory contains subdirectories, and if those subdirectories are empty.  To do this I get all the subdirectories and call the same method that is currently executing.  This provides a level of recursion that allows me to iteratively go through every subdirectory in a directory.  Since the existence of a subdirectory means that the directory is not empty, I automatically mark the current directory as not empty.

// look through directories recursively
DirectoryInfo[] dirs = directory.GetDirectories("*.*");
foreach (DirectoryInfo dir in dirs)
{
     scanForEmptyDirectories(dir);
     notEmpty = true;
}

Next, I add the directory path to a generic string collection so that I can later iterate through and delete the directories.  The code here is very simple:

private static List<string> directoriesToDelete;
directoriesToDelete = new List<string>();

...

if (!notEmpty)
{
    // add folder to collection
    directoriesToDelete.Add(directory.FullName);
}

This accomplished, I needed to write a method that logs empty directories, the deletion of directories, and errors.  I created a method that uses the StreamWriter and appends text to a file.  Very simple.

public static void logMessage(string logMessage)
{
    using (StreamWriter writer = File.AppendText(logFile))
    {
        writer.WriteLine(logMessage);
        writer.Flush();
    }
}

This method is called throughout the application, and writes any pertinent information to a log file (as you'll see below).

Now, to delete the directories, I iterate through my generic string collection.  Since some of my directories are marked as read-only, I elected to change the attributes of all directories marked for deletion to normal.  This removes the read-only flag, if it exists.  Next, I performed a similar operation on the files left in the directory (e.g. hidden files) and removed the read-only flag.  Once these two steps are complete, I can then delete the folder using the Delete method on the Directory object.

// iterate through the empty directories
foreach (string directory in directoriesToDelete)
{
    try
    {
        DirectoryInfo dir = new DirectoryInfo(directory);
        // set the attributes to normal; you cannot delete a readonly folder
        dir.Attributes = FileAttributes.Normal;

        string[] files = Directory.GetFiles(directory);
        // iterate through the files
        foreach (string file in files)
        {
            FileAttributes attributes = File.GetAttributes(file);
            if ((attributes & FileAttributes.ReadOnly) != 0)
            {
                // remove the readonly attribute from the files
                File.SetAttributes(file, ~FileAttributes.ReadOnly);
            }
        }

        // make sure to make the delete as recursive
        Directory.Delete(directory, true);
        // log the deletion
        logMessage(string.Format("Deleted: {0} ", directory));
    }
    catch (Exception e)
    {
        // log the error
        logMessage(string.Format("Error deleting: {0} ", directory));
        logMessage(string.Format("Error message: {0} ", e.Message));
        logMessage("Exiting application");
        // exit the console application
        Environment.Exit(0);
    }
}

Notice that I catch errors, log them, and then exit the application.  Also, the try/catch is embedded in the directory loop, so that the directory path can be included in the log (if it were the other way around, the directory path would be out of scope and unavailable).

Finally, given the above code, it is possible to make a parent directory empty by deleting its child directories.  To resolve this, I wrapped the execution of my code in a while statement that only exists when a given condition returns false.  This condition value returns false only if there hasn't been a single directory marked as empty.  If any directory is marked as empty, the application performs an additional scan following the deletion of the directories it found empty.  (Note: the runScan boolean value is a class-level variable that is set to true elsewhere in the code.)

while (runScan)
{
     // assume that we won't have to run again
     runScan = false;

     // if the value returns true, then run it again
     // it would return true 
     scanForEmptyDirectories(new DirectoryInfo(startingDirectory));
}

All in all, this was a very quick and efficient way to eliminate my empty music folders.  Your needs may be slightly different, so make changes accordingly.

I've gone ahead and included a zip file with the full source code for this console appliation.  Let me know if you have thoughts and/or suggestions!

EmptyFolders.zip (20.81 KB)

posted on Sunday, July 15, 2007 1:18:41 PM (Central Standard Time, UTC-06:00)  #    Comments [1] Trackback

My cousin Kai just got married yesterday in Maine.  I wasn't able to make it, but my parents and sister were able to fly up and attend.  By all accounts, it was a fantastic wedding and I wish we could have made it, but with a month old baby (not to mention her two-year-old sister) we just didn't feel like we could handle the trip.  And, given the multiple layovers and missed flights my parents encountered along the way, I think we made the right choice.

Still up in Maine, my dad called and said that he wanted to know the best way for all the attendees to share the great multitude of pictures that were taken.  He offered to use his corporate server to host the pictures, but I suggested that it would take a lot of work to write an interface to these pictures that was slick, intuitive, and made it easy for people to post, share, and view pictures.  Plus, there are a lot of great services out there, such as flickr, photobucket, and webshots (incidentally, doesn't anyone believe in capitalizing any more?).

Since we want to share both pictures AND video, I decided to go with webshots.  I can't say that I really love the interface, but it does seem to have all the necessary bells and whistles.

One thing I immediately noticed is that there does not appear to be any Web site that allows a community of users to post and manipulate the pictures of an album.  For instance, given my cousin's wedding as an example, I don't know of a Web site that would allow multiple people to register for the same album so that they could all upload and share pictures together.  The best solution I can think of is to create a new account, share the username and password with those interested in posting pictures, and distribute the URL to those that simply wish to view the pictures.

That said, I was asked to create said community, and share some simple instructions on how to both view the pictures, as well as upload new pictures.

View the pictures

  1. Open up your browser of choice.
  2. Browse to: http://community.webshots.com/user/kaisky2007/
  3. Select your album of choice (e.g. Wedding).

Upload new pictures

  1. Open up your browser of choice.
  2. Browse to: http://www.webshots.com/
  3. Enter the username and password in the upper right-hand corner, and click the "log in" button.  Feel free to  contact me if you need the login information.

    image
  4. After you are logged in, click the "upload" menu button.

    image
  5. Select an upload destination (or create a new album).  Personally, I'd recommend just using the existing "Wedding" album to keep it simple.

    image
  6. Click the "select files" button.  This will open a file dialog box.

    image
  7. Browse to the location of your pictures and/or videos.  Select the files you want to upload, and click the "Open" button.  You should see the selected files added to your file list.

    image
  8. Repeat steps 6 and 7 to add additional files.
  9. Once have added all your files, click the "upload" button.

    image
  10. You can now add a title and description to the pictures and videos you have uploaded.  The more information the better, so add some comments!  If you don't, then people that missed the wedding (like me!) won't know what I'm looking at.  Click the "save" button to save the title and description (or click "save all changes" below).

    image
  11. When you are done, you can click "view album" to look at your handiwork!

Pretty simple stuff!  I hope that someone in the family finds this information useful!

Congratulations, Kai and Sky!

posted on Sunday, July 15, 2007 11:00:48 AM (Central Standard Time, UTC-06:00)  #    Comments [0] Trackback
# Wednesday, June 13, 2007

I was browsing one of my new favorite websites, Microsoft's Script Repository, when I came upon the Add "Command Prompt Here" to Windows Explorer" Web page.  This script adds a "Command Prompt Here" command to the Windows Explorer system menu, so that if you select the command, a command window will open up in the same folder.  Nifty, eh?  Yes, I know, this has been around for quite awhile and is nothing new.  But, with a little twist, this can become a lot more useful.

Personally, I never use "cmd.exe" by itself.  I always use the "Visual Studio 2005 Command Prompt", as it has all the useful and fun PATHs already added to it.  So, with a small tweak to the script, we get the following enhancement:

Very handy!

Here's the script (it's so simple that I'm embarassed to share it!):

Set objShell = CreateObject("WScript.Shell")

objShell.RegWrite "HKCR\Folder\Shell\MenuText\Command\", _
    "cmd.exe ""C:\Program Files\Microsoft Visual Studio 8\VC\vcvarsall.bat"" x86 /k cd " & chr(34) & "%1" & chr(34)
objShell.RegWrite "HKCR\Folder\Shell\MenuText\", "VS.NET Command Prompt Here"

As I said, pretty simple, but oh so useful!

CommandPromptHere.vbs (.29 KB)

I hope this helps!

posted on Wednesday, June 13, 2007 8:40:11 PM (Central Standard Time, UTC-06:00)  #    Comments [0] Trackback

I'll be honest ... I'm lazy.  I hate doing repetitive things over, and over, and over again.  So, while I was going through and installing Commerce Server 2007 on a new virtual machine, I decided to script out the creation of the local user accounts.  Before we get to the script, a little background ...

It is recommended that you create multiple accounts to handle the various roles within Commerce Server (such as the four web services, staging, etc).  In a production environment, these should be created as Domain accounts; however, in development (or the virtual world) you may not have access to, or wish to use, a domain. Consequently, you can create these users as local accounts as well.

Below is a script that will go ahead and create these local users for you (if I have time I'll create a similar script for domain accounts).  Copy the text (or download the link) and save it to a .vbs file.  You should be able to simply double-click the file, and then open up Local Users and Groups under Computer Management to double-check.

' =====================================================
' Author:        Wade Wegner
' Create date:   06/13/2007
' Description:   Automate the creation of CS 2007 users
' File Name:     CreateCS2007LocalUsers.vbs

' =====================================================

' Set the local computer name
strComputer = "."

' Run the Load method
Load

' Encapsulates the processing of this script
Sub Load()

   ' Create the CS 2007 users
   CreateUser "CatalogWebSvc","Pa$$w0rd","Account for running the Catalog Web service"
   CreateUser "CSDMSvc","Pa$$w0rd","Account for running the Commerce Server Direct mailer service"
   CreateUser "CSHealthMonitorSvc","Pa$$w0rd","Account for running the Commerce Server health Monitoring service"
   CreateUser "CSLOB","Pa$$w0rd","Account for running the Commerce Server adapters"
   CreateUser "CSStageSvc","Pa$$w0rd","Account for running the Commerce Server Staging service"
   CreateUser "MarketingWebSvc","Pa$$w0rd","Account for running the Marketing Web service"
   CreateUser "OrdersWebSvc","Pa$$w0rd","Account for running the Orders Web service"
   CreateUser "ProfilesWebSvc","Pa$$w0rd","Account for running the Profiles Web service"
   CreateUser "RunTimeUser","Pa$$w0rd","IIS account for accessing a Commerce Server site or application"

   MsgBox "Complete!"

End Sub

' Create the local user
Sub CreateUser(userName, password, description)

   ' Check to see if the user exists; if so, then skip
   If NOT CheckIfUserExists(userName) Then
      Set objComputer = GetObject("WinNT://" & strComputer & "")
      Set objUser = objComputer.Create("user", userName)

      objUser.SetPassword password
      objUser.FullName = userName
      objUser.Description = description
      objUser.Put "UserFlags", 65600 ' Sets Password Never Expires to TRUE
      ' and sets User Can't Change Password to TRUE
      objUser.SetInfo
   Else
      MsgBox userName & " already exists!"
   End If

End Sub

' Check to see if user exists
Function CheckIfUserExists(userName)

   Set objComputer = GetObject("WinNT://" & strComputer & "")
   objComputer.Filter = Array("user")
   intFound = 0

   For Each User In objComputer
      If lcase(User.Name) = lcase(userName) Then
         intFound =
      End If 
   Next

   If intFound = 1 Then
      CheckIfUserExists = True
   Else
      CheckIfUserExists = False
   End If

End Function

And there you have it!

CreateCS2007LocalUsers.vbs (2.46 KB)

I hope someone else finds this useful!

posted on Wednesday, June 13, 2007 3:24:52 PM (Central Standard Time, UTC-06:00)  #    Comments [4] Trackback
# Tuesday, June 05, 2007

I often find myself curious as to what my rank/position on Google is, given a set of keywords.  For example, I know that if I search on my name "Wade Wegner" this blog comes up second (my personal site being first).  However, I sometimes wonder where my blog falls for other keywords, such as "commerce server 2007" or "biztalk server 2006".

So, I wrote this little tool to tell me!

This tool allows you to specify your URL (e.g. "http://blog.wadewegner.com/") and some keywords (e.g. "commerce server 2007") and tells you what number you are.  Currently, I have it scan only the first 1000 Google entries.

Useful, yes?

I realize it's a simple interface, but I just quickly slapped it together.

Any one know if this violates any of Googles terms of use?  I hope not!

Enjoy!

posted on Tuesday, June 05, 2007 10:17:21 PM (Central Standard Time, UTC-06:00)  #    Comments [0] Trackback
# Wednesday, May 23, 2007

As a consultant, I often have to spend a great deal of time diagnosing issues that are confronting my clients.  Over the years I've used some of the tools available from Sysinternals, but I honestly never put a lot of energy or time into really learning to use them.  On my most recent project, however, I've found them to be tremendously helpful, and I'm now a confirmed believer!

There are a number of useful tools available, and I don't profess to have used or mastered them all.  There are a few, however, that I strongly encourage you to familiarize yourself with:

  • Process Monitor - This montioring tool monitors the file system, Registry, processes, threads, and DLL activity in real-time.  Ever need to track down where data is getting written?  Ever wonder why you try to write or read from the Registry and receive errors?  This utility will help you track that down.  Process monitor is a combination of two older tools (Filemon and Regmon), and adds a whole slew of additional features such as rich and non-destructive filtering, comprehensive event properties such session IDs and user names, reliable process information, full thread stacks with integrated symbol support for each operation, simultaneous logging to a file, and more.

  • Process Explorer - Find out what files, registry keys and other objects processes have open, which DLLs they have loaded, and more. This utility will even show you who owns each process.  This tool is excellent for tracking down programs or processes that have locked files and directories.  It also has some powerful search capability that shows you which processes have handles opened or DLLs loaded.

  • BlueScreen Screen Saver - Okay, so this isn't a monitoring tool, but it's part of the Sysinternals suite and it's great!  Just load this up as the screen saver for your favorite person at work, sit back, and enjoy the show!

Take the time to explore the various tools that are available on the Sysinternals Web site.  There are a lot of tools that will make debugging and problem solving less of a hassle.

Best of luck!

posted on Wednesday, May 23, 2007 7:47:56 PM (Central Standard Time, UTC-06:00)  #    Comments [2] Trackback
# Tuesday, April 03, 2007

It's often nice, while working with BizTalk (or any other MS product, for that matter) to have UDL files available to allow you to quickly setup your connections to various databases.  A UDL file is essentially a file that saves connection information, making it available for future use.

To create a UDL file, follow these steps:

  1. Open a folder (or use the desktop) and create a new text file (right-click --> New --> Text Document).
  2. Rename the extension from ".txt" to ".udl".  Ignore the warning message.
  3. Double-click the new UDL file.
  4. Configure your database connection settings.

  5. Once you've been able to successfully test your connection, click the OK button.

That's it!  It's that simple!  Now your UDL file is available for future use.

Best of luck!

posted on Tuesday, April 03, 2007 8:32:28 PM (Central Standard Time, UTC-06:00)  #    Comments [4] Trackback
# Sunday, March 18, 2007

Thanks to a link from Joachim Lykke Andersen's DevTalk blog, I learned about a new blogging tool from Microsoft called "Windows Live Writer" (beta).  Check out the details from the Windows Live Writer team blog.

This seems to be a great tool, and one I believe I'll use religiously.  Check it out!

posted on Sunday, March 18, 2007 3:19:56 PM (Central Standard Time, UTC-06:00)  #    Comments [0] Trackback