<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>State Your Destination</title>
	<atom:link href="http://cmtybur.com/index.php/feed/" rel="self" type="application/rss+xml" />
	<link>http://cmtybur.com</link>
	<description>Observations on where software development can take you</description>
	<lastBuildDate>Fri, 26 Nov 2010 02:19:18 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.3</generator>
		<item>
		<title>Google instant preview = epic fail</title>
		<link>http://cmtybur.com/2010/11/25/google-instant-preview-epic-fail/</link>
		<comments>http://cmtybur.com/2010/11/25/google-instant-preview-epic-fail/#comments</comments>
		<pubDate>Fri, 26 Nov 2010 02:19:18 +0000</pubDate>
		<dc:creator>thisiscmt</dc:creator>
				<category><![CDATA[Musing]]></category>
		<category><![CDATA[Google]]></category>

		<guid isPermaLink="false">http://www.cmtybur.com/?p=203</guid>
		<description><![CDATA[I&#8217;ve been a fan of Google since 1999 or so, back when nobody knew who they were. I loved the simplicity of their site and how well their search techniques worked. And while they are still my favorite search engine, &#8230; <a href="http://cmtybur.com/2010/11/25/google-instant-preview-epic-fail/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been a fan of Google since 1999 or so, back when nobody knew who they were. I loved the simplicity of their site and how well their search techniques worked. And while they are still my favorite search engine, they recently added a feature that can only be described as horrible. I&#8217;m talking &#8216;I completely hate this, am I going to have to start using <a href="http://www.blekko.com">Blekko</a> now?&#8217; kind of horrible.</p>
<p>I&#8217;m talking about <a href="http://www.google.com/landing/instantpreviews">instant preview</a>, the snapshot of a given search result that pops up when you hover the mouse over it, or click the magnifying glass next to it. I didn&#8217;t mind the instant search feature they rolled out earlier this year. I used it for a couple of weeks until the constant screen updates as I edited the search box got annoying. And then I simply turned it off. For instant preview it&#8217;s not so simple. Oh you can sort of turn it off by closing the popup box, but as soon as you (inadvertently) click the screen near a search result, the popup returns.</p>
<p>I did some cursory searching and <strong>lots</strong> of people don&#8217;t like this feature, and they <strong>all</strong> wanted to know how to turn it off permanently. Google apparently hasn&#8217;t given users a clear way to do that, which makes me wonder what the heck is going on over there. First there was the Buzz lawsuit, and now search features you can&#8217;t disable. It&#8217;s a bad scene.</p>
<p>But there is hope if you are a Firefox user and have AdBlock Plus installed. You can add these three filters to stop instant preview for good:</p>
<p>google.com##.vspi<br />
google.com##.vspib<br />
google.com###vspb</p>
<p>They are working well so far. I shudder to think what new stuff is in the works.</p>
]]></content:encoded>
			<wfw:commentRss>http://cmtybur.com/2010/11/25/google-instant-preview-epic-fail/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hiding dialog box controls in InstallShield</title>
		<link>http://cmtybur.com/2010/09/16/hiding-dialog-box-controls-in-installshield/</link>
		<comments>http://cmtybur.com/2010/09/16/hiding-dialog-box-controls-in-installshield/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 19:35:52 +0000</pubDate>
		<dc:creator>thisiscmt</dc:creator>
				<category><![CDATA[Musing]]></category>
		<category><![CDATA[InstallShield]]></category>

		<guid isPermaLink="false">http://www.cmtybur.com/?p=193</guid>
		<description><![CDATA[I recently had to modify a Basic MSI installer created with InstallShield so it behaved differently if a certain value was passed in via the command line. That part was easy. What I needed to do next was figure out &#8230; <a href="http://cmtybur.com/2010/09/16/hiding-dialog-box-controls-in-installshield/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I recently had to modify a Basic MSI installer created with InstallShield so it behaved differently if a certain value was passed in via the command line. That part was easy. What I needed to do next was figure out how to alter the UI if that value was present, specifically to hide certain controls on a custom dialog.</p>
<p>You would think such a thing would be common and therefore it would be easy to deduce how to do it in InstallShield. Well, yes and no. After some web searching that didn&#8217;t get me very far, I was browsing around the Dialogs view in InstallShield 2010 and noticed that in the Behavior section for my custom dialog were three tabs at the bottom of the screen. They were labeled Events, Subscriptions, and Conditions, and though they didn&#8217;t *look* like tabs that is what they were. It turns out the Conditions tab was what I was after. From there I could specify the Hide action on my controls when a certain MSI property had a specific value. Not terribly intuitive, but I did find it eventually.</p>
<p>The trick will be remembering how I did it a year from now if I&#8217;m asked to modify the installer like that again.</p>
]]></content:encoded>
			<wfw:commentRss>http://cmtybur.com/2010/09/16/hiding-dialog-box-controls-in-installshield/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WPF browser applications</title>
		<link>http://cmtybur.com/2010/05/06/wpf-browser-applications/</link>
		<comments>http://cmtybur.com/2010/05/06/wpf-browser-applications/#comments</comments>
		<pubDate>Fri, 07 May 2010 00:18:25 +0000</pubDate>
		<dc:creator>thisiscmt</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[WPF]]></category>

		<guid isPermaLink="false">http://www.cmtybur.com/?p=186</guid>
		<description><![CDATA[I have written a number of WinForms applications over the years and while I think they&#8217;re pretty great, it&#8217;s hard to showcase them to the world at large. It occurred to me that it would be fantastic if there was &#8230; <a href="http://cmtybur.com/2010/05/06/wpf-browser-applications/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I have written a number of WinForms applications over the years and while I think they&#8217;re pretty great, it&#8217;s hard to showcase them to the world at large. It occurred to me that it would be fantastic if there was a way to somehow run one of these programs within a web browser. The research I did lead me to WPF XAML browser applications, which it turns out are a nifty way of doing just that.</p>
<p>My first and so far only attempt was a simple hosting application that had a single page with an iframe. Inside that iframe I loaded the XBAP file that referred to my WinForm app. The only real tricky part was retrofitting the app to be able to mostly do its thing in a restricted environment. But still, I&#8217;m fairly impressed that Microsoft makes this possible. It seems I should pay closer attention to WPF and what it can do.</p>
]]></content:encoded>
			<wfw:commentRss>http://cmtybur.com/2010/05/06/wpf-browser-applications/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Netbooks</title>
		<link>http://cmtybur.com/2010/01/15/netbooks/</link>
		<comments>http://cmtybur.com/2010/01/15/netbooks/#comments</comments>
		<pubDate>Sat, 16 Jan 2010 00:55:12 +0000</pubDate>
		<dc:creator>thisiscmt</dc:creator>
				<category><![CDATA[Musing]]></category>
		<category><![CDATA[Hardware]]></category>

		<guid isPermaLink="false">http://www.cmtybur.com/?p=161</guid>
		<description><![CDATA[Jeff Atwood had a post on his blog the other day about the overall awesomeness of netbooks, and how they signal a new era of open computing. I&#8217;m not sure I agree. I like the idea of an ultra-small laptop &#8230; <a href="http://cmtybur.com/2010/01/15/netbooks/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Jeff Atwood had a <a href="http://www.codinghorror.com/blog/archives/001318.html">post</a> on his blog the other day about the overall awesomeness of netbooks, and how they signal a new era of open computing. I&#8217;m not sure I agree.</p>
<p>I like the idea of an ultra-small laptop that is used primarily for running applications over the Internet. When I was shopping for a laptop last summer, I checked out the current crop of netbooks and seriously considered going in that direction. The problem is devices that size have limitations, which eventually made me go with a traditional, albeit small, laptop.</p>
<p>The biggest issues for me with netbooks are the too-small screen and the fact that they are still somewhat underpowered. I know the early EE, Dell, and Acer machines had screens around 10 inches. I guess Acer is now making one that&#8217;s slightly above 11, but that&#8217;s still tiny. I was afraid I&#8217;d be squinting to see details.</p>
<p>The Intel Atom seemed very cool, but I wanted the ability to run some heavyweight local applications if desired (think Visual Studio), and I worried the system would end up having sub-optimal performance. I hadn&#8217;t heard about Intel&#8217;s newest netbook CPUs, but dual-core certainly is an improvement. Still, for only a slightly larger form factor, I got a 2.6 GHz Core 2 Duo in my Dell Latitude.</p>
<p>As small as they are, they still aren&#8217;t as easy to take with you as a smartphone. Jeff considered having an inexpensive netbook and access to the Internet, without being chained to a wireless provider, to be a boon to computer users everywhere. But since wireless hotspots don&#8217;t exist everywhere yet, I don&#8217;t see how you can truly have the freedom to access the Internet wherever you want without going through one of the big wireless providers. I&#8217;ve been in lots of places without a hotspot but that did have T-mobile coverage, and I&#8217;ve often wished I had a broadband modem to connect.</p>
<p>Even though they are neat computers, truly, they aren&#8217;t going to be for everyone. </p>
]]></content:encoded>
			<wfw:commentRss>http://cmtybur.com/2010/01/15/netbooks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dell hardware replacement</title>
		<link>http://cmtybur.com/2010/01/15/dell-hardware-replacement/</link>
		<comments>http://cmtybur.com/2010/01/15/dell-hardware-replacement/#comments</comments>
		<pubDate>Fri, 15 Jan 2010 23:56:33 +0000</pubDate>
		<dc:creator>thisiscmt</dc:creator>
				<category><![CDATA[Musing]]></category>
		<category><![CDATA[Hardware]]></category>

		<guid isPermaLink="false">http://www.cmtybur.com/?p=163</guid>
		<description><![CDATA[So I bought a Dell Latitude E4300 laptop in June of 2009, the first laptop I&#8217;ve ever owned. It&#8217;s a beautiful machine, but a few months after I got it the keyboard started acting weird. Certain keys wouldn&#8217;t work right &#8230; <a href="http://cmtybur.com/2010/01/15/dell-hardware-replacement/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>So I bought a Dell Latitude E4300 laptop in June of 2009, the first laptop I&#8217;ve ever owned. It&#8217;s a beautiful machine, but a few months after I got it the keyboard started acting weird. Certain keys wouldn&#8217;t work right away after the system booted. They would start to work after a few minutes of endless tapping, as if there was some kind of short in the keyboard assembly. It slowly got worse and worse, to the point where I couldn&#8217;t log in any more.</p>
<p>It was still under warranty so I called Dell and figured I&#8217;d have to take it some place local or they would send a technician. Much to my surprise, they said I would be sent a new keyboard assembly and I could replace it myself. I have no problem with swapping out hardware components, I was just surprised that doing so has gotten so easy. Back in the day it could be a serious pain in the neck to replace certain parts on a laptop.</p>
<p>They had an online manual for removing the keyboard assembly and installing a new one. It took all of 2 minutes, and the new keyboard works great.</p>
<p>So thank you Dell, for making module parts that are easy to replace.</p>
]]></content:encoded>
			<wfw:commentRss>http://cmtybur.com/2010/01/15/dell-hardware-replacement/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SharePoint extensions for Visual Studio</title>
		<link>http://cmtybur.com/2010/01/03/sharepoint-extensions-for-visual-studio/</link>
		<comments>http://cmtybur.com/2010/01/03/sharepoint-extensions-for-visual-studio/#comments</comments>
		<pubDate>Sun, 03 Jan 2010 17:39:36 +0000</pubDate>
		<dc:creator>thisiscmt</dc:creator>
				<category><![CDATA[Musing]]></category>
		<category><![CDATA[SharePoint]]></category>

		<guid isPermaLink="false">http://www.cmtybur.com/?p=155</guid>
		<description><![CDATA[I&#8217;ve been using the SharePoint extensions for Visual Studio 2005/2008 for several months now, and after recently having a chance to see how some of the other tools work (WSPBuilder, STSDev, etc) I can safely say I like the extensions &#8230; <a href="http://cmtybur.com/2010/01/03/sharepoint-extensions-for-visual-studio/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been using the SharePoint extensions for Visual Studio 2005/2008 for several months now, and after recently having a chance to see how some of the other tools work (WSPBuilder, STSDev, etc) I can safely say I like the extensions best. The other tools do some great things, but they both assume you&#8217;re using C#, and all my SharePoint stuff is done in VB.NET.</p>
<p>Version 1.2 for Visual Studio 2005 was OK, but wasn&#8217;t as easy to work with as the superior version 1.3 for Visual Studio 2008. I haven&#8217;t seen any of the betas for Visual Studio 2010, but I&#8217;m hoping the built-in SharePoint tools they&#8217;ve created will be even easier to use.</p>
]]></content:encoded>
			<wfw:commentRss>http://cmtybur.com/2010/01/03/sharepoint-extensions-for-visual-studio/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows service management using WMI</title>
		<link>http://cmtybur.com/2009/09/26/windows-service-management-using-wmi/</link>
		<comments>http://cmtybur.com/2009/09/26/windows-service-management-using-wmi/#comments</comments>
		<pubDate>Sat, 26 Sep 2009 22:54:06 +0000</pubDate>
		<dc:creator>thisiscmt</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[VB.NET]]></category>
		<category><![CDATA[Windows service]]></category>
		<category><![CDATA[WMI]]></category>

		<guid isPermaLink="false">http://www.cmtybur.com/?p=124</guid>
		<description><![CDATA[After reading this post at StackOverflow, I realized that I was probably wrong to think it was OK to directly access the registry keys that Windows uses to keep track of installed services. Though the names and locations of the &#8230; <a href="http://cmtybur.com/2009/09/26/windows-service-management-using-wmi/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>After reading <a title="StackOverflow post" href="http://stackoverflow.com/questions/520517/changing-the-services-startup-type-windows" target="_blank">this post</a> at StackOverflow, I realized that I was probably wrong to think it was OK to directly access the registry keys that Windows uses to keep track of installed services. Though the names and locations of the keys probably won&#8217;t change any time soon, it&#8217;s always better to use a higher level of abstraction when dealing with Windows internals. In this case, WMI fits the bill very nicely.</p>
<p>I had not written any WMI-related code up til now, simply because I&#8217;ve always been able to find other methods to get the information I need. But after reading that post and knowing of a particular program of mine that <strong>does</strong> access the registry directly to determine the start mode for a service, I decided to re-write that code to use WMI via the  System.Management namespace in the .NET framework.</p>
<p>I came across a couple of different C# samples on the web and was able to modify them to fit my needs. Below is a new class I created for service management that will hopefully grow over time.</p>
<pre lang="vbnet">
Imports System.Management

Public Class ServiceManagement
    'Enumeration of service startup modes
    Public Enum ServiceStartMode
        Boot = 0
        System = 1
        Automatic = 2
        Manual = 3
        Disabled = 4
    End Enum

    'Return values for service-related WMI routines
    Public Enum ReturnValue
        Success = 0
        NotSupported = 1
        AccessDenied = 2
        DependentServicesRunning = 3
        InvalidServiceControl = 4
        ServiceCannotAcceptControl = 5
        ServiceNotActive = 6
        ServiceRequestTimeout = 7
        UnknownFailure = 8
        PathNotFound = 9
        ServiceAlreadyRunning = 10
        ServiceDatabaseLocked = 11
        ServiceDependencyDeleted = 12
        ServiceDependencyFailure = 13
        ServiceDisabled = 14
        ServiceLogonFailure = 15
        ServiceMarkedForDeletion = 16
        ServiceNoThread = 17
        StatusCircularDependency = 18
        StatusDuplicateName = 19
        StatusInvalidName = 20
        StatusInvalidParameter = 21
        StatusInvalidServiceAccount = 22
        StatusServiceExists = 23
        ServiceAlreadyPaused = 24
        ServiceNotFound = 25
    End Enum

    '''
<summary>
    ''' Gets the current start mode for the given service.
    ''' </summary>

    '''
<param name="sService">Name of an installed service.</param>
    ''' <returns>Numerical code indicating the service's start mode.</returns>
    Public Shared Function GetStartMode(ByVal sService As String) As ServiceStartMode
        Dim service As ManagementObject = Nothing
        Dim sServicePath As String
        Dim sStartMode As String

        GetStartMode = ServiceStartMode.Disabled

        Try
            sServicePath = String.Format("Win32_Service.Name=""{0}""", sService)
            service = New ManagementObject(sServicePath)
            sStartMode = service.GetPropertyValue("StartMode").ToString

            'We can't return the exact property value because StartMode will
            'show as 'Auto' rather than 'Automatic'. Since the ChangeStartMode
            'WMI method will need to have 'Automatic' passed when setting the
            'service to auto-start, our ServiceStartMode enum uses 'Automatic'
            Select Case sStartMode
                Case "Boot"
                    Return ServiceStartMode.Boot
                Case "System"
                    Return ServiceStartMode.System
                Case "Auto"
                    Return ServiceStartMode.Automatic
                Case "Manual"
                    Return ServiceStartMode.Manual
                Case "Disabled"
                    Return ServiceStartMode.Disabled
            End Select
        Catch
            Throw
        Finally
            If service IsNot Nothing Then
                service.Dispose()
            End If
        End Try
    End Function

    '''
<summary>
    ''' Sets the start mode for the given service.
    ''' </summary>

    '''
<param name="sService">Name of an installed service.</param>
    '''
<param name="nStartMode">Numerical code representing the new start mode.</param>
    ''' <returns>Error code indicating the result of the change operation.</returns>
    Public Shared Function SetStartMode(ByVal sService As String, ByVal nStartMode As ServiceStartMode) As ReturnValue
        Dim service As ManagementObject = Nothing
        Dim inParams As ManagementBaseObject = Nothing
        Dim outParams As ManagementBaseObject = Nothing
        Dim sServicePath As String

        SetStartMode = ReturnValue.UnknownFailure

        Try
            sServicePath = String.Format("Win32_Service.Name=""{0}""", sService)
            service = New ManagementObject(sServicePath)
            inParams = service.GetMethodParameters("ChangeStartMode")
            inParams("StartMode") = nStartMode.ToString()
            outParams = service.InvokeMethod("ChangeStartMode", inParams, Nothing)

            Return DirectCast([Enum].Parse(GetType(ReturnValue), outParams("ReturnValue").ToString()), ReturnValue)
        Catch
            Throw
        Finally
            If inParams IsNot Nothing Then
                inParams.Dispose()
            End If

            If outParams IsNot Nothing Then
                outParams.Dispose()
            End If

            If service IsNot Nothing Then
                service.Dispose()
            End If
        End Try
    End Function
End Class
</pre>
]]></content:encoded>
			<wfw:commentRss>http://cmtybur.com/2009/09/26/windows-service-management-using-wmi/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>An easy way to update DNN modules from another app</title>
		<link>http://cmtybur.com/2009/09/03/an-easy-way-to-update-dnn-modules-from-another-app/</link>
		<comments>http://cmtybur.com/2009/09/03/an-easy-way-to-update-dnn-modules-from-another-app/#comments</comments>
		<pubDate>Thu, 03 Sep 2009 13:43:57 +0000</pubDate>
		<dc:creator>thisiscmt</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[DotNetNuke]]></category>
		<category><![CDATA[VB.NET]]></category>

		<guid isPermaLink="false">http://www.cmtybur.com/?p=109</guid>
		<description><![CDATA[My thanks go out to Mitchel Sellers for informing me that DotNetNuke has a bulk install feature. I had a need to modify an existing Windows service so it could silently update some DNN modules. I was able to make &#8230; <a href="http://cmtybur.com/2009/09/03/an-easy-way-to-update-dnn-modules-from-another-app/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>My thanks go out to <a href="http://www.mitchelsellers.com/">Mitchel Sellers</a> for informing me that DotNetNuke has a bulk install feature. I had a need to modify an existing Windows service so it could silently update some DNN modules. I was able to make it work in this same service a couple years ago by modifying the DNN 4.3 source code to allow the main DotNetNuke.dll library to function outside of a web application (no easy feat, that). From there I could use the PaInstaller class to load a module. But then it wouldn&#8217;t work against 4.9.0 portals.</p>
<p>When I tried to do the same thing with the 4.9.0 source, it failed miserably. It just wouldn&#8217;t create an instance of SqlDataProvider, no matter how much I coaxed it. The better way was to have my service download the new module files (zips) to the installmodule folder under the portal&#8217;s root, create an HttpWebRequest to http://mysite/install/install.aspx?mode=installresources, then parse the response to check for success.</p>
<p>The response parsing was easier than I thought it would be. I did the bulk update first using a web browser so I could see what I was dealing with. It looked something like this:</p>
<img src="http://www.cmtybur.com/wp-content/uploads/2009/09/clip1.jpg" alt="Bulk install result" title="Bulk install result" width="468" height="316" class="size-full wp-image-143" />
<p>The HTML itself was nice in that it put non-blank space elements between each module name and result, so I could use Split to break everything out. I ignored the first two elements of the resultant array since it contained all the unimportant stuff before the list of modules, then simply looped over the array and verified the word Success was in each even-numbered element, like so:</p>
<pre lang="vbnet">
Dim aResults() As String

aResults = Split(sResponse, "&nbsp;")

If aResults.Length > 0 Then
    For i As Integer = 2 To aResults.Length - 1
        If i Mod 2 = 0 Then
            If Not aResults(i).Contains("Success") Then
                Return False
            End If
        End If
    Next i

    Return True
End If
</pre>
<p>I&#8217;m not sure why I had never heard of this feature over the course of developing several custom DNN modules, even though I&#8217;ve spent untold hours sifting through the forums at dotnetnuke.com and the Internet at large for detailed information on the portal&#8217;s architecture. In any case, that was the one new thing I learned that day.</p>
]]></content:encoded>
			<wfw:commentRss>http://cmtybur.com/2009/09/03/an-easy-way-to-update-dnn-modules-from-another-app/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>LDAP queries</title>
		<link>http://cmtybur.com/2009/08/08/ldap-queries/</link>
		<comments>http://cmtybur.com/2009/08/08/ldap-queries/#comments</comments>
		<pubDate>Sat, 08 Aug 2009 19:40:58 +0000</pubDate>
		<dc:creator>thisiscmt</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[LDAP]]></category>
		<category><![CDATA[VB.NET]]></category>

		<guid isPermaLink="false">http://www.cmtybur.com/?p=80</guid>
		<description><![CDATA[A recent project of mine required querying Active Directory for all the groups in which a given user is a member, or if there isn&#8217;t a domain then searching the local machine. It also had to return all groups defined &#8230; <a href="http://cmtybur.com/2009/08/08/ldap-queries/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>A recent project of mine required querying Active Directory for all the groups in which a given user is a member, or if there isn&#8217;t a domain then searching the local machine. It also had to return all groups defined in a given domain. In the course of putting the code together, I created a library for future projects that needed to perform such queries. I recently made a major improvement to the code that retrieves a user&#8217;s AD groups and thought it would be good to share what I have so far.</p>
<p>It&#8217;s based on some bits of code I found on the web. Initially GetADGroupMembership would only return the first-level Active Directory groups the user was in, but that&#8217;s no good if the user is in a group that is in another group that is in yet another group that&#8217;s the one you really care about. So I added some recursion to bring up the entire group chain. It seems to perform well enough with our domain, which admittedly doesn&#8217;t have a great deal of nesting.</p>
<pre lang="vbnet">
Imports System.DirectoryServices

Public Class LDAP
    Public Shared Function GetADGroupMembership(ByVal sPath As String, ByVal sUserID As String) As List(Of String)
        Dim lstResults As List(Of String)
        Dim lstGroups As List(Of String)
        Dim lstSubGroups As List(Of String)
        Dim sFilter As String

        GetADGroupMembership = Nothing

        sFilter = "(&#038;(objectClass=user)(samAccountName=" &#038; sUserID &#038; "))"
        lstResults = RunSearch(sPath, sFilter, "MemberOf")
        lstGroups = New List(Of String)

        If lstResults IsNot Nothing Then
            For Each result As String In lstResults
                lstGroups.Add(result)
                lstSubGroups = GetADGroupMembershipByGroup(sPath, result)

                For Each sSubGroup As String In lstSubGroups
                    If Not lstGroups.Contains(sSubGroup) Then
                        lstGroups.Add(sSubGroup)
                    End If
                Next sSubGroup
            Next result
        End If

        Return lstGroups
    End Function

    Public Shared Function GetLocalGroupMembership(ByVal sPath As String, ByVal sUserName As String, ByVal sPassword As String) As List(Of String)
        Dim de As DirectoryEntry = Nothing
        Dim colGroups As Object
        Dim lstGroups As List(Of String)

        GetLocalGroupMembership = Nothing

        Try
            de = New DirectoryEntry(sPath, sUserName, sPassword, AuthenticationTypes.Secure)
            colGroups = de.Invoke("Groups")
            lstGroups = New List(Of String)

            For Each o As Object In colGroups
                lstGroups.Add(o.Name)
            Next o

            Return lstGroups
        Catch
            Throw
        Finally
            If de IsNot Nothing Then
                de.Dispose()
            End If
        End Try
    End Function

    Public Shared Function GetADGroups(ByVal sPath As String) As List(Of String)
        Dim lstGroups As List(Of String)
        Dim sFilter As String

        GetADGroups = Nothing

        sFilter = "(&#038;(objectClass=group))"
        lstGroups = RunSearch(sPath, sFilter)
        lstGroups.Sort()

        Return lstGroups
    End Function

    Private Shared Function GetADGroupMembershipByGroup(ByVal sPath As String, ByVal sGroupName As String) As List(Of String)
        Dim lstResults As List(Of String)
        Dim lstGroups As List(Of String)
        Dim lstSubGroups As List(Of String)
        Dim sFilter As String

        GetADGroupMembershipByGroup = Nothing

        sFilter = "(&#038;(objectCategory=group)(cn=" &#038; sGroupName &#038; "))"
        lstResults = RunSearch(sPath, sFilter, "MemberOf")
        lstGroups = New List(Of String)

        If lstResults IsNot Nothing Then
            For Each result As String In lstResults
                lstGroups.Add(result)

                'Retrieve all groups that the current group is a member of
                lstSubGroups = GetADGroupMembershipByGroup(sPath, result)
                For Each sSubGroup As String In lstSubGroups
                    If Not lstGroups.Contains(sSubGroup) Then
                        lstGroups.Add(sSubGroup)
                    End If
                Next sSubGroup
            Next result
        End If

        Return lstGroups
    End Function

    Private Shared Function RunSearch(ByVal sPath As String, ByVal sFilter As String, Optional ByVal sProperty As String = "") As List(Of String)
        Dim lstResults As List(Of String)
        Dim de As System.DirectoryServices.DirectoryEntry = Nothing
        Dim deSearcher As System.DirectoryServices.DirectorySearcher = Nothing
        Dim results As System.DirectoryServices.SearchResultCollection
        Dim res As System.DirectoryServices.SearchResult

        RunSearch = Nothing

        Try
            de = New System.DirectoryServices.DirectoryEntry(sPath)
            deSearcher = New System.DirectoryServices.DirectorySearcher(de)
            deSearcher.Filter = sFilter
            deSearcher.SearchScope = SearchScope.Subtree
            results = deSearcher.FindAll

            lstResults = New List(Of String)

            For Each res In results
                If sProperty = "" Then
                    'If no specific property is being sought, simply return the common name
                    lstResults.Add(TrimToName(res.GetDirectoryEntry.Name))
                Else
                    For Each o As Object In res.Properties(sProperty)
                        lstResults.Add(TrimToName(o))
                    Next o
                End If
            Next res

            Return lstResults
        Catch
            Throw
        Finally
            If deSearcher IsNot Nothing Then
                deSearcher.Dispose()
            End If

            If de IsNot Nothing Then
                de.Dispose()
            End If
        End Try
    End Function

    Private Shared Function TrimToName(ByVal path As String) As String
        Dim parts() As String

        parts = path.Split(",")
        Return parts(0).Replace("CN=", String.Empty)
    End Function
End Class</pre>
]]></content:encoded>
			<wfw:commentRss>http://cmtybur.com/2009/08/08/ldap-queries/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL 2008 and the Case of the Misplaced Activity Monitor</title>
		<link>http://cmtybur.com/2009/05/06/sql-2008-and-the-case-of-the-misplaced-activity-monitor/</link>
		<comments>http://cmtybur.com/2009/05/06/sql-2008-and-the-case-of-the-misplaced-activity-monitor/#comments</comments>
		<pubDate>Thu, 07 May 2009 03:57:23 +0000</pubDate>
		<dc:creator>thisiscmt</dc:creator>
				<category><![CDATA[Musing]]></category>
		<category><![CDATA[SQL Server]]></category>

		<guid isPermaLink="false">http://www.cmtybur.com/?p=63</guid>
		<description><![CDATA[We have several new training servers where I work running Windows 2008 and SQL Server 2008. They are the only production machines we have running SQL 2008, and though they work fine, my experience with the latest version of SQL &#8230; <a href="http://cmtybur.com/2009/05/06/sql-2008-and-the-case-of-the-misplaced-activity-monitor/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>We have several new training servers where I work running Windows 2008 and SQL Server 2008. They are the only production machines we have running SQL 2008, and though they work fine, my experience with the latest version of SQL Server has made me wonder why anyone would be eager to upgrade from 2005.</p>
<p>I don&#8217;t know what major new features went into SQL 2008, but I do know one big thing that changed in Management Studio and it&#8217;s not good. I present exhibit A: the activity monitor. Previous versions of SQL Server had a place where you could see all the processes running on the server. It was handy because you could quickly tell who had locks on what database, find out if there were any processes that were blocking or being blocked, and you could end a process that couldn&#8217;t be ended through natural means. Yet somehow Microsoft decided that was all too simple.</p>
<p>First they moved it out of the object explorer and into the context menu of the database server itself, where nobody would think to look. I had to turn to Google to determine how you open it. Then once you start it you&#8217;re greeted with one of the worst user interfaces I&#8217;ve ever seen. You have to click on the Processes pane to show processes. All the columns of information are in one fixed-width grid with no horizontal scroll bar, so if you want to widen one it will come at the expense of narrowing another. And there are 16 columns! They have filter options in the column headers that dynamically allow you to filter by values in the column, which is all well and good, but the headers are more clunky than anything else. And finally, the grid defaults to only using about a third the vertical space of the window, and that&#8217;s <strong>all you get</strong>.</p>
<p>In short, it&#8217;s horrible and evil. I&#8217;m amazed that they would take something that was so easy to use and make it so unpleasant. Maybe I haven&#8217;t spent enough time with it,and maybe it&#8217;s due to the fact that we have the Express version, but if it&#8217;s really no more than what I&#8217;ve seen, I pray there will be some other tools out there that can show you the same information in a much better package.</p>
]]></content:encoded>
			<wfw:commentRss>http://cmtybur.com/2009/05/06/sql-2008-and-the-case-of-the-misplaced-activity-monitor/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

