Wednesday, November 4, 2009

SQL Stuff!

OK kids, time for some stupid SQL tricks. Actually these are mostly things that I don't use that often so it's hard to keep them memorized when I do need them. I have these in a Sharepoint list but you don't have access to that, so here they are.

1. First, converting date formats. Sometimes you need to store the day without the time, and sometimes you need to return a string that does not contain the time.

This converts '1/1/2000 4:20 PM' into '1/1/2000 12:00 AM', which is the actual value of the date without the time:
Convert(datetime, Convert(varchar(15), getdate(), 101))

This converts '1/1/2000 4:20 PM' into '1/1/2000':
Convert(varchar(15), getdate(), 101)

2. Another useful command is when you suddenly discover that the log file has grown out of control because the default recovery model is Full and you're not using Backup Exec with the SQL Agent to backup your database. If your database is not mission-critical and you're OK with restoring from last night's backup in the event of a complete disk failure/database corruption/etc., you can set the recovery model to Simple. However the log file won't shrink until a full SQL-aware backup has been performed. If you don't care and just need to shrink it now, it's a two-step process.

backup log [dbname] with truncate_only
dbcc shrinkfile('[logname]', 63)

It's important to note that the '[logname]' is not the filename, nor is it the name of the database, it's the Logical Name listed in the Files section of the Database properties. Enclose it in single quotes since it is a string value, not an object. However [dbname] is the object name of the database without quotes just like "use [dbname]". This DBCC command shrinks it to about 64 MB. Just make sure you perform a full SQL backup before running this.

3. Cursors! Cursors should be avoided whenever possible, they are not efficient and produce a load on the server, etc, etc. But sometimes there is no other choice when you need to loop through a recordset. So obviously since we don't use cursors that often, it's hard to remember the exact syntax. Here is a little template to make it easier:

DECLARE @[var1] varchar(8)
DECLARE [cursorname] CURSOR
SELECT [column1] FROM [table]
OPEN [cursorname]
FETCH NEXT FROM [cursorname] INTO @[var1]
FETCH NEXT FROM [cursorname] INTO @[var1]
CLOSE [cursorname]
DEALLOCATE [cursorname]

4. Ever have a large database with lots of stored procedures and you're trying to remember where that one awesome piece of code that you wrote last year was used? Well if you can remember some of the code you can search for it!


5. Migrated a bunch of databases to a new version of SQL and want to upgrade the databases themselves? Also want to switch them to Simple recovery mode? That's easy. First you can make a list of all databases and those settings:

SELECT name, compatibility_level, is_auto_shrink_on, recovery_model_desc FROM sys.databases
where is_auto_shrink_on=1 or recovery_model=1 or compatibility_level<90

(use compatibility_level<100 if you're on SQL 2008)

Then assuming you've tested them under the new system and everything is good to go, or maybe you're just one of those people that likes to upgrade first and fix issues later...

EXEC dbo.sp_dbcmptlevel @dbname=N'[dbname]', @new_cmptlevel=90

(again, @new_cmptlevel=100 for SQL 2008)

6. And finally, if you need to know if a temp table exists:

IF OBJECT_ID('tempdb..#temptablename') IS NOT NULL

Guitar scales

Time for a break from the IT stuff! I've been playing guitar for about 23 years and although I don't really give lessons, I often come across people who are picking it up and want to know more, or maybe they know a bunch of songs and want to learn more about soloing. I made up a cool little cheat sheet that shows the fretboard and the notes for the scales, I'm sure there are plenty of similar things on teh Interwebs but this is something I would just draw on a piece of paper in about 10 minutes. I recently created it in Notepad and it fits nicely on a single sheet of paper when you print it. It should be pretty self-explanatory if you know how to read tablature and chord fingerings.

E minor/G Major

All positions

0 3 5 7 9 12

Open position 2nd position

0 3 5 3 5 7
|---|-F#|-G-|---|-A-| |---|-G-|---|-A-|---|-B-|
|-C-|---|-D-|---|-E-| |---|-D-|---|-E-|---|-F#|
G|---|-A-|---|-B-|---| |-A-|---|-B-|-C-|---|---|
D|---|-E-|---|-F#|---| |-E-|---|-F#|-G-|---|---|
A|---|-B-|-C-|---|---| |-B-|-C-|---|-D-|---|---|
E|---|-F#|-G-|---|---| |-F#|-G-|---|-A-|---|---|

3rd position 5th position

3 5 7 5 7 9
|---|---|-A-|---|-B-|-C-| |---|---|-B-|-C-|---|-D-|
|---|---|-E-|---|-F#|-G-| |---|---|-F#|-G-|---|-A-|
|---|-B-|-C-|---|-D-|---| |-C-|---|-D-|---|-E-|---|
|---|-F#|-G-|---|-A-|---| |-G-|---|-A-|---|-B-|---|
|-C-|---|-D-|---|-E-|---| |-D-|---|-E-|---|-F#|---|
|-G-|---|-A-|---|-B-|---| |-A-|---|-B-|-C-|---|---|

7th position Chords

7 9 12 1 3 5 7
|---|-C-|---|-D-|---|-E-| E : E G B D (Em, Em7)
|---|-G-|---|-A-|---|-B-| F#: F# A C E (F#º, F#º m7)
|-D-|---|-E-|---|-F#|---| G : G B D F# (G, GM7)
|-A-|---|-B-|-C-|---|---| A : A C E G (Am, Am7)
|-E-|---|-F#|-G-|---|---| B : B D F# A (Bm, Bm7)
|-B-|-C-|---|-D-|---|---| C : C E G B (C, CM7)
D : D F# A C (D, D7)

E : Aeolian (Minor)
F#: Locrian (partially diminished, Minor with flat 5 & 2)
G : Ionian (Major)
A : Dorian (Minor with raised 6)
B : Phrygian (Minor with lowered 2)
C : Lydian (Major with raised 4)
D : Mixolydian (Major with lowered 7)

[Page Break]

A minor/C Major

All positions

0 3 5 7 9 12

Open position 2nd position

0 3 5 1 3 5 7
|-F-|---|-G-|---|-A-| |---|-G-|---|-A-|---|-B-|
|-C-|---|-D-|---|-E-| |---|-D-|---|-E-|-F-|---|
G|---|-A-|---|-B-|---| |-A-|---|-B-|-C-|---|---|
D|---|-E-|-F-|---|---| |-E-|-F-|---|-G-|---|---|
A|---|-B-|-C-|---|---| |-B-|-C-|---|-D-|---|---|
E|-F-|---|-G-|---|---| -F-|---|-G-|---|-A-|---|---|

3rd position 5th position

3 5 7 5 7 9
|---|---|-A-|---|-B-|-C-| |---|---|-B-|-C-|---|-D-|
|---|---|-E-|-F-|---|-G-| |---|-F-|---|-G-|---|-A-|
|---|-B-|-C-|---|-D-|---| |-C-|---|-D-|---|-E-|---|
|-F-|---|-G-|---|-A-|---| |-G-|---|-A-|---|-B-|---|
|-C-|---|-D-|---|-E-|---| |-D-|---|-E-|-F-|---|---|
|-G-|---|-A-|---|-B-|---| |-A-|---|-B-|-C-|---|---|

7th position Chords

7 9 12 1 3 5 7
|---|-C-|---|-D-|---|-E-| A : A C E G (Am, Am7)
|---|-G-|---|-A-|---|-B-| B : B D F A (Bº, Bº m7)
|-D-|---|-E-|-F-|---|---| C : C E G B (C, CM7)
|-A-|---|-B-|-C-|---|---| D : D F A C (Dm, Dm7)
|-E-|-F-|---|-G-|---|---| E : E G B D (Em, Em7)
|-B-|-C-|---|-D-|---|---| F : F A C E (F, FM7)
G : G B D F (G, G7)

A : Aeolian (Minor)
B : Locrian (partially diminished, Minor with flat 5 & 2)
C : Ionian (Major)
D : Dorian (Minor with raised 6)
E : Phrygian (Minor with lowered 2)
F : Lydian (Major with raised 4)
G : Mixolydian (Major with lowered 7)

[Page Break]

D minor/F Major

All positions

0 3 5 7 9 12
E |-F-|---|-G-|---|-A-|-Bb|---|-C-|---|-D-|---|-E-|
G |---|-A-|-Bb|---|-C-|---|-D-|---|-E-|-F-|---|-G-|
D |---|-E-|-F-|---|-G-|---|-A-|-Bb|---|-C-|---|-D-|
A |-Bb|---|-C-|---|-D-|---|-E-|-F-|---|-G-|---|-A-|
E |-F-|---|-G-|---|-A-|-Bb|---|-C-|---|-D-|---|-E-|

Open position 1st position

0 3 5 1 3 5
|-F-|---|-G-|---|-A-| |---|---|-G-|---|-A-|-Bb|
|-C-|---|-D-|---|-E-| |---|---|-D-|---|-E-|-F-|
G |---|-A-|-Bb|---|---| |---|-A-|-Bb|---|-C-|---|
D |---|-E-|-F-|---|---| |---|-E-|-F-|---|-G-|---|
A |-Bb|---|-C-|---|---| |-Bb|---|-C-|---|-D-|---|
E |-F-|---|-G-|---|---| |-F-|---|-G-|---|-A-|---|

3rd position 5th position

3 5 7 5 7 9
|---|---|-A-|-Bb|---|-C-| |---|-Bb|---|-C-|---|-D-|
|---|---|-E-|-F-|---|-G-| |---|-F-|---|-G-|---|-A-|
|-Bb|---|-C-|---|-D-|---| |-C-|---|-D-|---|-E-|---|
|-F-|---|-G-|---|-A-|---| |-G-|---|-A-|-Bb|---|---|
|-C-|---|-D-|---|-E-|---| |-D-|---|-E-|-F-|---|---|
|-G-|---|-A-|-Bb|---|---| |-A-|-Bb|---|-C-|---|---|

7th position Chords

7 9 12 1 3 5 7
|---|-C-|---|-D-|---|-E-| D : D F A C (Dm, Dm7)
|---|-G-|---|-A-|-Bb|---| E : E G Bb D (Eº, Eº m7)
|-D-|---|-E-|-F-|---|---| F : F A C E (F, FM7)
|-A-|-Bb|---|-C-|---|---| G : G Bb D F (Gm, Gm7)
|-E-|-F-|---|-G-|---|---| A : A C E G (Am, Am7)
-Bb|---|-C-|---|-D-|---|---| Bb: Bb D F A (Bb, BbM7)
C : C E G Bb (C, C7)

D : Aeolian (Minor)
E : Locrian (partially diminished, Minor with flat 5 & 2)
F : Ionian (Major)
G : Dorian (Minor with raised 6)
A : Phrygian (Minor with lowered 2)
Bb: Lydian (Major with raised 4)
C : Mixolydian (Major with lowered 7)

Login scripts

While we're on the subject of VBS scripting, I have written some login scripts that can map drives and printers based on group membership, username, OU, etc. so you no longer need to have different scripts for different groups/OUs in Active Directory:

On Error Resume Next
Set oWSH = CreateObject("WScript.Shell")
Set oNet = CreateObject("WScript.Network")
Set oFS = CreateObject("Scripting.FileSystemObject")

sUsername = LCase(oNet.Username)
sComputerName = oWSH.ExpandEnvironmentStrings("%COMPUTERNAME%")
sMyDocs = "\\fileserver\users\" & sUsername & "\My Documents\"

Set oRootDSE = GetObject("LDAP://rootDSE")
Set oConnection = CreateObject("ADODB.Connection")
oConnection.Open "Provider=ADsDSOObject;"
Set oCommand = CreateObject("ADODB.Command")
oCommand.ActiveConnection = oConnection
oCommand.CommandText = " ">;(&(objectCategory=User)(samAccountName=" & sUsername & "));distinguishedName;subtree"
Set oRecordSet = oCommand.Execute
sDistinguishedName = oRecordSet.Fields("DistinguishedName")

Set oUser = GetObject("LDAP://" & sDistinguishedName)
oGroups = oUser.GetEx("memberOf")
bFinance = False
bAP = False
bSD = False
For Each g In oGroups
If InStr(g, "Finance")> 0 Then bFinance = True
If InStr(g, "Accounts Payable")> 0 Then bAP = True
If InStr(g, "San Diego")> 0 Then bSD = True

'Map drive for everyone
oNet.MapNetworkDrive "S:", "\\fileserver\shared"

'Map drive by group
If bFinance Then
oNet.MapNetworkDrive "P:", "\\fileserver\finance"
End If

'Map printers by group
If bAP Then
oNet.AddWindowsPrinterConnection "\\printserver\HP4100_AP"
oNet.AddWindowsPrinterConnection "\\printserver\Canon3380"
End If

'Map printer by location and computername prefix
If bSD And Left(sComputerName, 3) = "VDI" Then
oNet.AddWindowsPrinterConnection "\\printserver\HP6300_SD"
End If

'Map drive for one user on one workstation
If sUsername = "jsmith" And sComputerName = "VDI-XP-013" Then
oNet.MapNetworkDrive "P:", "\\fileserver\marketing"
End If

'Map drive for administrator
If sUsername = "administrator" Then
oNet.RemoveNetworkDrive "T:"
oNet.MapNetworkDrive "T:", "\\fileserver\install"
End If

'Make sure My Documents was created under home dir
If Not oFS.FolderExists(sMyDocs) then
End If

'Map printer for single user
If sUsername = "sjones" Then
oNet.AddWindowsPrinterConnection "\\sjones\hp_p1006"
End If

Function FindMapped(sLetter, sShare)
bFound = False
Set oDrives = oNet.EnumNetworkDrives
For i = 0 to oDrives.Count - 1 Step 2
If LCase(oDrives.Item(i)) = LCase(sLetter) Then
bFound = (LCase(oDrives.Item(i+1)) = LCase(sShare))
End If
FindMapped = bFound
End Function

Desktop Settings

As an IT Consultant I typically logon to many different servers and workstations and have found myself adjusting the default desktop settings hundreds, maybe thousands, of times to set my preferences. I absolutely hate the default settings provided by Microsoft and can't stand doing even simple file management tasks with those settings. Who the heck thought Large Icons in folders was a good idea anyway? And hiding file extensions has got to be the stupidest idea anyone ever thought of. Anyone remember annakournikova.jpg.vbs? Thanks, Microsoft for making our users even stupider.

Anyway I spent some time building a VBS script to set all of my personal preferences in one shot. I store this file on my web server as a .txt file in case I'm at a client who has VBS downloads disabled, which is a pretty good idea in general. I just memorize the URL, download it to the desktop, change the file extension to .vbs, and run it. Some of the settings require explorer.exe to be closed so rather than kill the process with Task Manager, there is an easier way that lets it shut down cleanly. First open a cmd window or Task Manager, then go to Start, Shutdown, hold down Ctrl-Shift-Alt, and click Cancel. This will shut down explorer.exe and allow you to make the modifications. Using cmd or Task Manager's File | Run command, type in the path to the VBS file and run it. Then you can launch explorer.exe and view your changes.

Pretty much all the settings modify the current user profile so it's safe to use on a machine that is used by someone else if you're logging on with different credentials. It does some fun things like telling IE that it has already run the welcome screen, sets my tab defaults and home page, disables the Outlook tray notifications, expands all of the Start Menu folders, sets Explorer to List View, increases the taskbar to two lines and turns on the clock (Terminal Servers hide the clock by default), lock the taskbar, shows the hidden desktop icons, gets rid of that stupid Language Bar, and removes the lame default sorting of the Start Menu.

Most of the registry keys are pretty self-explanatory but some need clarification. StuckRects2 is a binary value that controls the taskbar, clock, and some other settings. I just copied the values from a system that is set exactly the way I want it and hardcoded the hex values into aStuckRects. Streams is another binary value that controls the folder view customizations (I like List view by default). Deleting a registry key with subkeys is not possible with RegDelete so there is a function to help with that. I'm sure there are a lot of annoying startup programs that I'm missing, I add them as I come across them.

Here is the current version of my VBS file as of this posting. You can also download my latest version at

'Create Objects
Set oWSH = CreateObject("WScript.Shell")
Set oNet = CreateObject("WScript.Network")
Set oReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")

'Define constants and values for long registry keys
Const HKEY_CURRENT_USER = &H80000001
sUsername = LCase(oNet.Username)
sOLTray03 = "HKCU\SOFTWARE\Microsoft\Office\11.0\Outlook\Display Types\Balloons"
sOLTray07 = "HKCU\SOFTWARE\Microsoft\Office\12.0\Outlook\Display Types\Balloons"
sRunU = "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
sRunM = "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
sIE = "HKCU\Software\Microsoft\Internet Explorer"
sExp = "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer"
sStream = "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Streams"
sStuckRects = "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\StuckRects2"

'Set personal settings
aStream = Array(&H08,&H00,&H00,&H00,&H03,&H00,&H00,&H00,_
aStuckRects = Array(&H28,&H00,&H00,&H00,&HFF,&HFF,&HFF,&HFF,_
sHomePage = ""

On Error Resume Next

'Outlook Settings
oWSH.RegWrite sOLTray03 & "\Exchange", 0, "REG_DWORD"
oWSH.RegWrite sOLTray03 & "\NetConn", 0, "REG_DWORD"
oWSH.RegWrite sOLTray03 & "\NetWarn", 0, "REG_DWORD"
oWSH.RegWrite sOLTray07 & "\Exchange", 0, "REG_DWORD"
oWSH.RegWrite sOLTray07 & "\NetConn", 0, "REG_DWORD"
oWSH.RegWrite sOLTray07 & "\NetWarn", 0, "REG_DWORD"

'Windows Explorer/Desktop Settings
oWSH.RegWrite sExp & "\Advanced\EnableBalloonTips", 0, "REG_DWORD"
oWSH.RegWrite sExp & "\Advanced\Start_AdminToolsRoot", 2, "REG_DWORD"
oWSH.RegWrite sExp & "\Advanced\StartMenuAdminTools", 1, "REG_DWORD"
oWSH.RegWrite sExp & "\Advanced\Start_LargeMFUIcons", 0, "REG_DWORD"
oWSH.RegWrite sExp & "\Advanced\Start_NotifyNewApps", 0, "REG_DWORD"
oWSH.RegWrite sExp & "\Advanced\Start_ShowHelp", 0, "REG_DWORD"
oWSH.RegWrite sExp & "\Advanced\Start_ShowMyComputer", 2, "REG_DWORD"
oWSH.RegWrite sExp & "\Advanced\Start_ShowControlPanel", 2, "REG_DWORD"
oWSH.RegWrite sExp & "\Advanced\Start_ShowMyDocs", 2, "REG_DWORD"
oWSH.RegWrite sExp & "\Advanced\Start_ShowMyMusic", 0, "REG_DWORD"
oWSH.RegWrite sExp & "\Advanced\Start_ShowMyPics", 0, "REG_DWORD"
oWSH.RegWrite sExp & "\Advanced\Start_ShowNetConn", 2, "REG_DWORD"
oWSH.RegWrite sExp & "\Advanced\Start_ShowNetPlaces", 1, "REG_DWORD"
oWSH.RegWrite sExp & "\Advanced\Start_ShowPrinters", 1, "REG_DWORD"
oWSH.RegWrite sExp & "\Advanced\Start_ShowRun", 1, "REG_DWORD"
oWSH.RegWrite sExp & "\Advanced\TaskbarSizeMove", 0, "REG_DWORD"
oWSH.RegWrite sExp & "\Advanced\StartMenuFavorites", 2, "REG_DWORD"
oWSH.RegWrite sExp & "\Advanced\ServerAdminUI", 1, "REG_DWORD"
oWSH.RegWrite sExp & "\Advanced\HideFileExt", 0, "REG_DWORD"
oWSH.RegWrite sExp & "\Desktop\CleanupWiz\NoRun", 1, "REG_DWORD"
oWSH.RegWrite sExp & "\HideDesktopIcons\NewStartPanel\{20D04FE0-3AEA-1069-A2D8-08002B30309D}", 0, "REG_DWORD"
oWSH.RegWrite sExp & "\HideDesktopIcons\NewStartPanel\{450D8FBA-AD25-11D0-98A8-0800361B1103}", 0, "REG_DWORD"
oWSH.RegWrite sExp & "\HideDesktopIcons\NewStartPanel\{208D2C60-3AEA-1069-A2D7-08002B30309D}", 0, "REG_DWORD"
oWSH.RegWrite sExp & "\HideDesktopIcons\NewStartPanel\{871C5380-42A0-1069-A2EA-08002B30309D}", 0, "REG_DWORD"
oWSH.RegWrite "HKCU\Software\Microsoft\CTF\LangBar\ShowStatus", 3, "REG_DWORD"
oReg.SetBinaryValue HKEY_CURRENT_USER, sStream, "Settings", aStream
oReg.SetBinaryValue HKEY_CURRENT_USER, sStuckRects, "Settings", aStuckRects
oWSH.RegWrite sIE & "\Main\StatusBarOther", 1, "REG_DWORD"

'Internet Explorer Settings
oWSH.RegWrite sIE & "\Main\Start Page", sHomePage, "REG_SZ"
oWSH.RegWrite sIE & "\Main\AlwaysShowMenus", 0, "REG_DWORD"
oWSH.RegWrite sIE & "\Main\RunOnceHasShown", 1, "REG_DWORD"
oWSH.RegWrite sIE & "\Main\IE8RunOncePerInstallCompleted", 1, "REG_DWORD"
oWSH.RegWrite sIE & "\Main\IE8TourShown", 1, "REG_DWORD"
oWSH.RegWrite sIE & "\Main\IE8RunOnceLastShown", 1, "REG_DWORD"
oWSH.RegWrite sIE & "\TabbedBrowsing\Groups", 0, "REG_DWORD"
oWSH.RegWrite sIE & "\TabbedBrowsing\NewTabPageShow", 1, "REG_DWORD"
oWSH.RegWrite sIE & "\TabbedBrowsing\OpenInForeground", 1, "REG_DWORD"
oWSH.RegWrite sIE & "\TabbedBrowsing\PopupsUseNewWindow", 0, "REG_DWORD"
oWSH.RegWrite sIE & "\TabbedBrowsing\ShowTabsWelcome", 0, "REG_DWORD"
oWSH.RegWrite sIE & "\TabbedBrowsing\UseHomepageForNewTab", 1, "REG_DWORD"
oWSH.RegWrite sIE & "\TabbedBrowsing\WarnOnClose", 0, "REG_DWORD"
oWSH.RegWrite sIE & "\PhishingFilter\Enabled", 0, "REG_DWORD"
oWSH.RegWrite sIE & "\PhishingFilter\EnabledV8", 0, "REG_DWORD"
oWSH.RegWrite "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\IEHarden", 0, "REG_DWORD"
oWSH.RegWrite "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\IEHardenIENoWarn", 0, "REG_DWORD"

'Delete registry entries including annoying startup programs
DeleteRegEntry HKEY_CURRENT_USER, "Software\Microsoft\Windows\CurrentVersion\Explorer\MenuOrder\Start Menu2"
DeleteRegEntry HKEY_CURRENT_USER, "Software\Microsoft\Windows\CurrentVersion\Explorer\MenuOrder\StartMenu"
DelReg "\MsnMsgr"
DelReg "\AdobeUpdater"
DelReg "\Adobe Reader Speed Launcher"
DelReg "\DVDLauncher"
DelReg "\SunJavaUpdateSched"
DelReg "\My Web Search Bar Search Scope Monitor"
DelReg "\MyWebSearch Email Plugin"
DelReg "\iTunesHelper"
DelReg "\QuickTime Task"
DelReg "\HP Software Update"
DelReg "\HPUsageTracking"
DelReg "\BrStsWnd"

Sub DelReg(key)
oWSH.RegDelete sRunU & key
oWSH.RegDelete sRunM & key
End Sub

Function DeleteRegEntry(sHive, sEnumPath)
' Attempt to delete key. If it fails, start the subkey enumeration process.
lRC = oReg.DeleteKey(sHive, sEnumPath)

' The deletion failed, start deleting subkeys.
If (lRC <> 0) Then
lRC = oReg.EnumKey(sHive, sEnumPath, sNames)

For Each sKeyName In sNames
If Err.Number <> 0 Then Exit For
lRC = DeleteRegEntry(sHive, sEnumPath & "\" & sKeyName)

' At this point we should have looped through all subkeys, trying to delete the registry key again.
lRC = oReg.DeleteKey(sHive, sEnumPath)
End If
End Function

Welcome to my blog

Hopefully I'll make regular postings here, I tend to get into it for a while then forget about it, then come back to it again later. My goal for this is to provide some technical information that I've come across in my many years as an IT Consultant, helpful tips and programming samples that have made my life easier.