Why I dont want XM radio

Here is my short list...

1) If Im paying for radio, why am I still sitting through 20 minutes of advertisements on some channels? In particular, the comedy channel where every ad starts with "SIZE MATTERS", or "GET CHEAP VIAGRA at ____.com", or the ever more ridiculous date a cougar ads. Is the implication that just because I like uncensored comedy I am an impotent sex addict with a small penis who cant find a date with older women?!?!?!?

GOOD GRIEF! I wont even mention how much I hate the name "Raw Dog" for the comedy channel...

2) If Im paying for radio, nay the NEXT GENERATION beyond FM- XM!!! radio why cant I listen to it in a parking garage like am radio circa 1910???

3) Its too damn expensive for me to flip through the 15 or so channels that suit my needs to find something to listen to. Its like channel surfing on a much grander scale...

4) Im a dont call me, I will call you kinda guy. So seriously, XM, DONT CALL ME. no I mean it- STOP CALLING ME. Furthermore, stop prank calling me! If I get one more hang up from 877 253 3846 Im going to write a blog about it or something... o_O
Get enough people to staff your call center that when you robo dial me, I dont get 10 hangups before I can say "NO!".

5) Let me pick my channels a'la carte for a much reduced fee and so I dont have to go from channel 6 to 150 on my factory radio that was not designed to perform such operations without alot of manual effort...

Sid Vicious - Get a sid from an AD object, and a basic C# Active Directory tutorial

Summary: Sid Vicious is a tool developed to get the Security Identifier of Active Directory Users and objects without the need to install or use ADSI edit. This tool was originally designed to assist my brother who heads the systems access team of a large company, but I think it also makes for a great tutorial on connection to and query information from Active Directory using C# .NET

The Code: This is broken down in to 4 parts; 1) Required .NET Namespaces/References 2) The connection to Active Directory, 3) The collection/handling of the SID, and 4) The Interface/glue code.

Step One: .NET Prerequisites

Connections to Active Directory are managed using a reference to the System.DirectoryServices.dll. Though there are other methods available, such as using the ActiveDS com library, for this purpose we will be using System.DirectoryServices. Secondly, to translate the SID from a byte array to usable text, we need to reference the System.Security.Principal namespace in our codefile.

Step Two: Connecting to Active Directory

Using the Directory Services library, connecting to AD is quick and easy. While using the app.config is the normal route for configuring the connection, with just slightly more effort, you can make your code completely portable. To do this, you need to connect to the global catalog to discover and get the RootDse. RootDse is the root of a directory server, and is included with LDAP 3.0 and provides a handy method for getting metadata about the directory server. For more information about RootDse, see here or here.

The Code:

Connecting to the Global Catalog: First you need to create a Directory Entry object pointing to the root path of the Global catalog.

DirectoryEntry ADConnection = null;
using (DirectoryEntry RootDse = new DirectoryEntry("GC:"))
    {
        foreach (DirectoryEntry root in RootDse.Children)
        {
            ADConnection = root;
            break;
        }
    }

So here we get the first Directory Entry object in the global catalog("GC:") and assign it to the Directory Entry "ADConnection" we have created. This is our connection to Active Directory. As you can see, no LDAP path is necessary and this code should work for any environment that has a Global Catalog server.

Querying Active Directory: Now that we have a Directory Entry connection to Active Directory, we can query the catalog.

The Code:

using (ADConnection)
    {
        DirectorySearcher DS = new DirectorySearcher();
        SearchResult SR;
        DS.SearchRoot = ADConnection;
        DS.SearchScope = SearchScope.Subtree;
        DS.Filter = "(&(|(objectClass=User)(objectClass=Group)
        (objectClass=Computer))
        (|(samAccountName=" + SearchString + ")
        (name=" + SearchString + ")(dn=" + SearchString + ")
        (displayName=" + SearchString + ")))";
        DS.SizeLimit = 1000;
        DS.PageSize = 1000;
        SR = DS.FindOne();
        if (SR != null)
        {
            _deUser = SR.GetDirectoryEntry();
            string sid = GetSid(_deUser);
            if (!String.IsNullOrEmpty(sid))
            {
                textBox1.Text = sid;
            }
            else
            {
                textBox1.Text = "null sid returned";
            }
        }
        else
        {
            textBox1.Text = "Object Not Found";
        }
    }

Here is the play by play: 1) Wrap the ADConnection in a using statement, this is the syntactic equivalent of a try/finally statement.

2) Create a Directory Searcher object- this object performs our query.

3) Create a Search Result object- this will be populated by our query should it produce a result.

4) Initialize the Directory Searcher parameters-

SearchRoot = the catalog root

SearchScope = the depth of the search of the catalog. There is an enumeration that provides the 3 values available: base(the root object, and ONLY the root object), OneLevel(the base object plus one hiearchical level down), Subtree(recursively through the entire directory tree)

Filter = this specifies the types of objects and text filters we want to apply to the search. The syntax of the search string is a function of And Or operators, grouped by parenthesis. In this case, we want a pretty broad filter that will return Computer, Group and User objects. We then will query based on several directory attributes: samAccountName, name, distinguishedName, or displayName. The format is as such:(&(|(ObjectType1)(ObjectType2)(ObjectType3))(|(SearchAttribute1)(SearchAttribute2) (SearchAttribute3)(SearchAttribute4)))

Here is the filter string I used for this example:

DS.Filter = "(&(|(objectClass=User)(objectClass=Group)
        (objectClass=Computer))
        (|(samAccountName=" + SearchString + ")
        (name=" + SearchString + ")(dn=" + SearchString + ")
        (displayName=" + SearchString + ")))";

So notice that we are using the OR qualifier for the object class portion of the filter, we want Users, Groups and Computers. We use the same OR qualifier for the Attributes we are searching. The samAccountName is more commonly known as the User ID, the name attribute is the same as common name(cn) example Craig Albright, the distinguished name(dn) attribute is basically the fully qualified name of the AD object. (example CN=Craig Albright, OU=User Accounts, DC=domain, DC=com) Display Name is typically used to set a name value if a user has a preferred name to his/her given name.

DS.SizeLimit = 1000;

This sets the number of objects that should be returned by the directory searcher. In this case we are only dealing with 1 object at a time but it is nice to be aware of this setting, for the cases when wildcard searches are needed. Also note that Domain Controllers have a similar setting on the server side that can limit the number of returned results.

DS.PageSize = 1000;

This property is used if you want to Page the result set from the directory search. This sets a "cursor" of sorts to the Domain Controller to let it know where it left off. (useful for returning results in conjunction with the "refreshCache" method for paging.)

SR = DS.FindOne();

This method returns the first object returned from active directory as a "SearchResult" object. All we need to do to get the sid is get the Directory Entry for this object, which is accomplished thusly:

if (SR != null)
        {
          _deUser = SR.GetDirectoryEntry();
           string sid = GetSid(_deUser);
        }

So we first check to make sure the SearchResult is not null, then call the GetDirectoryEntry() method which returns a DirectoryEntry object based on the SearchResult context. the next line is where we get the objects SID. I created the GetSid method, which converts the byte array stored in the DirectoryEntry "objectSid" property. The code for GetSid is listed below in Part Three.

Step Three: getting the SID.

This is the method used to get the string value of the Sid.

private string GetSid(DirectoryEntry _deUser)
        {
           byte[] sidBytes = (byte[])_deUser.Properties["objectSid"].Value;
           SecurityIdentifier userSid = new SecurityIdentifier(sidBytes, 0);
           return userSid.ToString();
        }

This is a pretty simple method: it accepts the directory entry object, gets/casts the value of the objectSid property to a byte array, and finally creates a SecurityIdentifier object based on this byte array. This particular constructor uses a byte array and offset parameter signifying the start index of the SID. For our purposes, an offset of 0 is passed. Finally, we use the ToString() method of userSid to return the SID value in text form.

Step Four: The Glue/GUI code

Most of the code listed above comes from the event handler delegate named SearchButton_Click. SearchButton is the trigger for all the activity in this application. To make the form, open the designer, drag a text box onto the form, name it SearchStringTxt. Drag a button to the form, name it SearchButton, set the button text to "Get Sid!". Drag another TextBox to the form, name it SidResultBox. Optionally you can drag a label above each text box and describe their functions. When finished, the GUI should look like this:

ScreenShot

So thats it, now you can create an application that connects to Active Directory and retrieves a user/computer/group. Here is the full source:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.DirectoryServices;
using System.Security.Principal;

namespace SIDVicious
{
    public partial class SidVicious : Form
    {
        public SidVicious()
        {
            InitializeComponent();
        }

        private void SearchButton_Click(object sender, EventArgs e)
        {
            try
            {
                string SearchString = SearchStringTxt.Text;
                DirectoryEntry _deUser;
                DirectoryEntry AD = null;
                using (DirectoryEntry RootDse = new DirectoryEntry("GC:"))
                {
                    foreach (DirectoryEntry root in RootDse.Children)
                    {
                        AD = root;
                        break;
                    }
                }
                using (AD)
                {
                    DirectorySearcher DS = new DirectorySearcher();
                    SearchResult SR;
                    DS.SearchRoot = AD;
                    DS.SearchScope = SearchScope.Subtree;
                    DS.Filter = "(&(|(objectClass=User)(objectClass=Group)
                    (objectClass=Computer))(|(samAccountName=" + SearchString + ")
                    (name=" + SearchString + ")(dn=" + SearchString + ")
                    (displayName=" + SearchString + ")))";
                    DS.SizeLimit = 1000;
                    DS.PageSize = 1000;
                    SR = DS.FindOne();
                    if (SR != null)
                    {
                        _deUser = SR.GetDirectoryEntry();
                        string sid = GetSid(_deUser);
                        if (!String.IsNullOrEmpty(sid))
                        {
                            SidResultBox.Text = sid;
                        }
                        else
                        {
                            SidResultBox.Text = "null sid returned";
                        }
                    }
                    else
                    {
                        SidResultBox.Text = "Object Not Found";
                    }
                }
            }
            catch (Exception ex)
            {
                SidResultBox.Text = ex.Message;
            }
            

        }

        private string GetSid(DirectoryEntry _deUser)
        {
           byte[] sidBytes = (byte[])_deUser.Properties["objectSid"].Value;
           SecurityIdentifier userSid = new SecurityIdentifier(sidBytes, 0);
           return userSid.ToString();
        }
    }
}

Compile, run, modify, expand upon, and/or enjoy to your hearts delight. Hopefully this has been a helpful tutorial for doing some basic Active Directory Querying. Feel free to let me know what you think.

If you just want a SID gathering tool without the trouble, download it Here

Expanded Fun with HP Printers

Click here to download:
PrinterFun.zip (17 KB)

Inspired by this article I decided that the concept could be taken a bit further.  As such, I decided to mine an Rss feed to turn our printer into an Rss feed reader of sorts.  Ok, well an rss feed headline reader anyway.  There is alot more that could be done here, but think of the possibilities- each printer in your office could have a different personality.  :)  The gossiper, the nerd, the music geek.  The possibilities are endless.  I took the liberty to refactor the original code somewhat to use the newer DNS host resolution, and moved the IP address from input args to an app.config.  You can also specify the rss feed url in this config file.  Anyway, as specified in the original article, this will work with HP printers only, and it seems that if your particular printer has a display that can support it, you can exceed the 16 character limit imposed by the original code.  Have fun.