GUIDs and octet strings (converting between them)

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, 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


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


They can also look like the following:



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


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

    [Guid]$g = New-Object Guid;
    if([Guid]::TryParse($Guid, [ref]$g))
        return ([System.String]::Join('', ($g.ToByteArray() | ForEach-Object { $_.ToString('x2') })).ToUpper());
        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

    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;
        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;

#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);
        throw new InvalidOperationException("Input value violates octet string validation pattern (32-character hexidecimal string expected).");

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


About Paul Williams

IT consultant working for Microsoft specialising in Identity Management and Directory Services.
This entry was posted in Programming, Scripting and tagged , , , , , . Bookmark the permalink.

5 Responses to GUIDs and octet strings (converting between them)

  1. Pingback: Open a Socket! » Blog Archive » [ERROR] Could not find the Exchange Mailbox Administrators Universal Security Group through its well-known GUID

  2. Howdy Paul – just been looking at doing a variation on this, where I want to read the objectGUID from an AD LDAP query result into a GUID property, and ended up with the following function which seems to work nicely for me (so far):

    Function Convert-ArrayToGuid ([System.Array]$byteArr) {
    $guidAsString = “”
    [int]$pos = 0
    $byteArr | ForEach-Object {
    $pos += 1
    if ($pos -in (5,7,9,11)) { $guidAsString += “-“}
    $guidAsString += $_.ToString(‘x2′).ToUpper()

    e.g. Convert-ArrayToGuid -byteArr $($ADObj.Properties.objectguid[0])

    (where $ADObj is a member of the collection returned from a DirectoryServices.DirectorySearcher.FindAll() call. I am thinking that the above could also be “nicer” if I didn’t have to insert “-” characters in positions 5,7,9,11 like I have.

    Thanks for the post!

  3. David says:

    Here are some one liners for converting
    For example To Convert from the canonical form to Octet String
    [System.String]::Join(”,(( new-object system.guid(‘8c4ac332-975f-4717-ad7b-ba4a4e968fff’) ).ToByteArray() | ForEach-Object { $_.ToString(‘x2’) } ) )

  4. mlourh says:

    Thank you Paul and David,
    very helpful link,

  5. Pingback: Getting the script name from ARS | clan8blog

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s