Quantcast
Channel: Programming – Hybrid Identity
Viewing all articles
Browse latest Browse all 6

GUIDs and octet strings (converting between them)

$
0
0

I’ve been working on a relatively simple synchronisation project that consists of two Active Directory Domain Services (AD DS) forests (the source forest, a single label root domain and three child domains; and the target forest, a single domain forest with a proper Internet routable DNS namespace) and Windows Azure Active Directory (AAD), a.k.a. Office 365.  There’s not much to say here except that in-scope objects are being migrated between the forests using Quest Migration Manager (QMM).  Some of the mailboxes are linked mailboxes, others are not.  I’m using the example code that ships with the AAD connector, currently in beta and on connect.microsoft.com, so am obviously joining the linked mailbox users to the users in the account forest using objectSid – msExchMasterAccountSid == objectSid.  Because we will decommission FIM when the migration is complete and move over to DIRSYNC (it’s operationally cheaper) the target forest – the account forest – must be the source of authority, i.e. the immutable ID or source anchor must be the objectGuid of the objects from this directory.  That’s fine, we’ll pre-create objects in the target forest using QMM, join those to source objects and treat them just like linked mailboxes – the solution will flow account attributes from target and mail attributes from source and when we turn off FIM we’ll enable DIRSYNC and all will be well as the immutable IDs are GUIDs in the target forest.

Why am I telling you this?  Well QMM stamps either adminDisplayName, if it’s not an Exchange forest, or one of the extensionAttributes if it is an Exchange forest, with the GUID of the source object.  Except it uses the octet string format AD DS administrators might be accustomed to.  So the join logic is now a tad more painful.  We need to handle GUID as octet string == adminDisplayName, or adminDisplayName as GUID == GUID.  One is easy, documented everywhere.  The other conversion – taking an octet string and converting it back to your typical string representation of a GUID, less so.  The purpose of this post?  Code snippets.  Smile

GUIDs

Let’s take a step back.  GUIDs generally look like this:

234ed3af-58e3-46b0-8cc1-2e1e86b3bf67

They can also look like the following:

{234ed3af-58e3-46b0-8cc1-2e1e86b3bf67}

234ED3AF58E346B08CC12E1E86B3BF67

Octet strings look like this (this is the same GUID as the examples above):

AFD34E23E358B0468CC12E1E86B3BF67

OK, so how does one transform one format to another?  Not as easily as you might think.

Converting a GUID to an octet string in PowerShell

System.Guid has a ToString method that gives you the various formats of the GUID.  Getting the octet string is a bit more work, trivialised through examples – here’s my PowerShell function, based on the .NET documentation or various blogs:

# convert a string GUID into an octet (hex) string GUID (like you would use to query AD)
function Convert-GuidToOctetString
{
    param
    (
        [String]$Guid
    );

    [Guid]$g = New-Object Guid;
    if([Guid]::TryParse($Guid, [ref]$g))
    {
        return ([System.String]::Join('', ($g.ToByteArray() | ForEach-Object { $_.ToString('x2') })).ToUpper());
    }
    else
    {
        throw Exception("Input string is not a valid GUID")
    }

}

The crux of that is this, assuming $g is a System.Guid object:

[System.String]::Join(”, ($g.ToByteArray() | ForEach-Object { $_.ToString(‘x2’) })).ToUpper()

OK, how about the other way round?  How do we take an octet string and turn it into a proper GUID?  Smile with tongue out

Converting an octet string into a GUID in PowerShell

Well, after a lot of Internet searching I finally ran out of joy using Bing, so I cracked open a quality Riesling and wrote the following, which works as best I can tell:

# convert an octet string guid to a typical string GUID
function Convert-OctetStringToGuid
{
    param
    (
        [String]$Guid
    );

    if(32 -eq $guid.Length)
    {
        [UInt32]$a = [Convert]::ToUInt32(($guid.Substring(6, 2) + $guid.Substring(4, 2) + $guid.Substring(2, 2) + $guid.Substring(0, 2)), 16)
        [UInt16]$b = [Convert]::ToUInt16(($guid.Substring(10, 2) + $guid.Substring(8, 2)), 16)
        [UInt16]$c = [Convert]::ToUInt16(($guid.Substring(14, 2) + $guid.Substring(12, 2)), 16)

        [Byte]$d = ([Convert]::ToUInt16($guid.Substring(16, 2), 16) -as [byte])
        [Byte]$e = ([Convert]::ToUInt16($guid.Substring(18, 2), 16) -as [byte])
        [Byte]$f = ([Convert]::ToUInt16($guid.Substring(20, 2), 16) -as [byte])
        [Byte]$g = ([Convert]::ToUInt16($guid.Substring(22, 2), 16) -as [byte])
        [Byte]$h = ([Convert]::ToUInt16($guid.Substring(24, 2), 16) -as [byte])
        [Byte]$i = ([Convert]::ToUInt16($guid.Substring(26, 2), 16) -as [byte])
        [Byte]$j = ([Convert]::ToUInt16($guid.Substring(28, 2), 16) -as [byte])
        [Byte]$k = ([Convert]::ToUInt16($guid.Substring(30, 2), 16) -as [byte])

        [Guid]$g = New-Object Guid($a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k)

        return $g.Guid;
    }
    else
    {
        throw Exception("Input string is not a valid octet string GUID")
    }
}

There’s probably better ways of doing that, but it works.  Now I can happily interchange and write some join rules…

Converting a GUID to and from an octet string in .NET (C#)

Here’s the same functions written in C#.  I just used these on an engagement.

#region ConvertGuidToOctetString

// ConvertGuidToOctetString takes a typical System.Guid string
// and converts into the octet string format, e.g.
//   e148d33e-670a-41ef-b704-e78d40e9a5f6 becomes
//   3ED348E10A67EF41B704E78D40E9A5F6

public static String ConvertGuidToOctetString(Guid gUID)
{
    return ConvertGuidToOctetString(gUID.ToString());
}

// Parse is used instead of TryParse as there's no point catching
// an exception to throw it again in this instance
public static String ConvertGuidToOctetString(String gUID)
{
    Guid guid = Guid.Parse(gUID);
    String g = String.Empty;

    foreach (var b in guid.ToByteArray())
    {
        g += String.Format("{0:X2}", b);
    }

    return g;
}
#endregion

#region ConvertOctetStringToGuid

// ConvertOctetStringToGuid takes an octet string and converts it
// into a System.Guid GUID.

public static Guid ConvertOctetStringToGuid(String gUID)
{
    String pattern = @"^(?i)[0-9A-F]{32}";
    if (Regex.IsMatch(gUID, pattern))
    {
        UInt32 a = Convert.ToUInt32((gUID.Substring(6,2) +
            gUID.Substring(4,2) + gUID.Substring(2,2) + gUID.Substring(0,2)), 16 );

        UInt16 b = Convert.ToUInt16((gUID.Substring(10, 2) + gUID.Substring(8, 2)), 16);
        UInt16 c = Convert.ToUInt16((gUID.Substring(14, 2) + gUID.Substring(12, 2)), 16);

        Byte d = (Byte)Convert.ToUInt16(gUID.Substring(16, 2), 16);
        Byte e = (Byte)Convert.ToUInt16(gUID.Substring(18, 2), 16);
        Byte f = (Byte)Convert.ToUInt16(gUID.Substring(20, 2), 16);
        Byte g = (Byte)Convert.ToUInt16(gUID.Substring(22, 2), 16);
        Byte h = (Byte)Convert.ToUInt16(gUID.Substring(24, 2), 16);
        Byte i = (Byte)Convert.ToUInt16(gUID.Substring(26, 2), 16);
        Byte j = (Byte)Convert.ToUInt16(gUID.Substring(28, 2), 16);
        Byte k = (Byte)Convert.ToUInt16(gUID.Substring(30, 2), 16);

        return new Guid(a, b, c, d, e, f, g, h, i, j, k);
    }
    else
    {
        throw new InvalidOperationException("Input value violates octet string validation pattern (32-character hexidecimal string expected).");
    }
}
#endregion

I added some basic validation to the .NET methods.  More could be added.  Note also that Parse and TryParse were added to System.Guid in .NET 4.

Feel free to show me better ways of doing this.  I’m not a programmer, and was enjoying a glass or two when I wrote these!  Winking smile



Viewing all articles
Browse latest Browse all 6

Latest Images

Trending Articles





Latest Images