Posts

So, as the long-winded title infers, today I’ll be covering something that I wrote a long time ago and have recently re-written (albeit, probably badly) for you to use and/or learn from.

In this case, we’re using a PowerShell script, which JITs C# code, the C# code calls into an unmanaged DLL (C++), and that calls into an Windows API. Once the data has been obtained from the Windows API, we pass the data back from the unmanaged assembly to the managed code (via Marshal) and then return that back to the PowerShell instance to be displayed to the user.

Before we dive into the what we’re doing, we should cover some key concepts. The first is JIT’ing. JIT stands for “Just-In-Time” (Compilation) and the name is slightly a misnomer but we’ll cover that in a second. So, in JIT, what happens is that the run time precompiles the code before it’s ran. This is important because a key-concept in exception handling is the runtime’s seek operation to find a handler for an exception that is thrown. You’ll often see this as a FirstChanceException in a dump file. In PowerShell, we have the added ability to leverage the JIT compilation by passing source code as a type into the App’s Domain. It’s important to distinguish that once the App Domain has been disposed of, the type specified is lost and has to be re-instantiated again.

So, what – exactly – is this code going to be doing? Well, since Windows Vista, the Windows Operating System exposes the Wait Chain Traversal API. You can see a demonstration of this API in Task Manager: Go to the Details tab, right click on a process and click “Analyze Wait Chain”.

Since Windows Server 2016 Core doesn’t include a desktop or any GUI interfaces, a more robust way was needed to obtain the same information in production, to determine if the reason an application wasn’t responding or performing work was because the threads were blocked.

When you run the code, you can tell if this is the case or not by something like the following:

12972 [7464:12972:blocked]->[ThreadWait]->[7464:12968:blocked]->[End]

Where the first thread is blocked by a thread wait on the the second thread, which is also (itself) blocked.

So, first things first, the PowerShell code. Take a peek here to see that. Note that the Source code is contained with a specific character-delimited string @”<code>”@. After that we add a Type, pointing it to the source code we’ve defined and referencing the assemblies that we’ll need for this type to work. Worthy of noting is that when we add this type, it is exposed in PowerShell the same way any normal .NET type is, via the []:: convention.

Note that in the C# source we import the unmanaged DLL and reference the exposed method. In the body of the code, we also construct an IntPtr to reference for the return. So, now, we get to Marshalling.

An IntPtr is, quite literally, a pointer or handle to an object. A pointer is a reference to memory where an object exists and the object is typically delimited by characters to signify the termination of it (e.g.: the end of a string is null-terminated). A handle is roughly the same premise but the handle abstracts memory management from the caller. So, at 200 ticks, the handle could point to address 0x000001 and at 369 ticks, it could point to 0x34778.

Alright, so why this matters is because when we pass from unmanaged code back to managed code, there’s nothing that implicitly tells the managed code where to find the object in native memory; so, we have to pass a pointer to the object back to managed (I believe managed creates it’s own copy and creates an address for that object) and, using that, we can then try to convert the passed object from a native string into a managed string (via Marshalling).

What about this unmanaged code I keep hearing about? Oh, well… You can find that here. Don’t forget to add the headers referenced in stdafx.h, or your compiler will cry bloody murder.

So, how this works is: The script is called via PowerShell. After some magic to verify that we weren’t given junk data, then PowerShell JIT’s the C# code and performs the runtime operations. The compiler loads the unmanaged DLL into memory. The C# code then calls into the unmanaged DLL via the exposed method (declspec/dllexport/cdecl). The unmanaged code performs it’s work and returns the string back to the caller – unaware that the caller is managed code. The managed code creates an IntPtr to reference the return and then Marshal is called to convert the native string into a managed string. This is then returned back to the user. In the case of multiple instances of a process, the managed string is added to an array and that array is returned.

While it may not seem like much and seem like overglorified complication just to check for threads on wait chaings, it was code that was written to be used in production where we had no desktop environments and we had to determine if this was the case.

Have you ever wanted to find out which computers are on your local network, what their IP addresses are (if you’re using DHCP), and what their hostnames are? Well, I’ve written a PowerShell script to do just that!

If the Prefix parameter is supplied, it attempts to find all hosts in the last octet range (0-255) that are up (e.g.: that respond to pings) and then uses DNS to attempt to resolve the IP address to a known hostname. This can be especially useful for things like trying to find your Plex server, if your router has restarted and you don’t have a static IP address assigned for it.

If the Prefix parameter is not supplied, we attempt to obtain the first IP address available to the system (indexing by zero from the array) and use that range (e.g.: 192.168.0.x) to find the local hosts that are up (e.g.: responding to pings) and attempt to resolve their names in DNS.

The script takes some time to process the entire range and that’s because I didn’t want to deal with trying to add to a collection in a thread-safe manner due to parallelisation in PowerShell. It would be easy enough to do in C# and, if there’s a lot of interest in that, I could devote some time to writing this to be a dynamic-link library, instead.

It has come to my attention that an explanation of how the values are calculated is necessary in order to help you understand why you would have “differing” values than those defined in the table below.

First, you need to understand what bitwise flags are. Essentially, bitwise flags allow you to have multiple values for an enum type, based on their sum. The linked article discussing bitwise flags on enumerators gives code examples of how and why this might be done.

Second, the specific reason why we give you the hex value is so that you can do the calculation to determine what enum values satisfy the property’s value (as the integer representation that you’re seeing).

So, in the specific example that was presented to me, a customer couldn’t understand why they would have a value of ’97’ for the RemoteRecipientType. In this case, it would be the values of SharedMailbox (0x60) and ProvisionedMailbox (0x1) being added together (meaning/inferring that the mailbox is a shared mailbox that was provisioned in the cloud and was not migrated from on-premises).

0x60 [96] + 0x1 [1] = 0x61 [97]

If needed, you can use PowerShell and it will convert the sum of the hex numbers to an integer value for you, automatically. Try the following in PowerShell to see what I mean: 0x60 + 0x1

Original Post:

Often, in O365, there’s a reference field we use to specify what a recipient type is, as far as on-premises AD/Exchange is concerned. If you weren’t already aware, this is how the attributes relate:

Like many other Active Directory Attributes, these are represented by Integer Values in Active Directory. One important item to note here is that you do not want to arbitrarily change these values: the Recipient Display Type is something that should only be set by Exchange. Changing it via any other method is not supported.

Here is how the Recipient Display Type Breaks down:

Display Type

Value

MailboxUser

0

DistributionGroup

1

PublicFolder

2

DynamicDistributionGroup

3

Organization

4

PrivateDistributionList

5

RemoteMailUser

6

ConferenceRoomMailbox

7

EquipmentMailbox

8

ArbitrationMailbox

10

MailboxPlan

11

LinkedUser

12

RoomList

15

SecurityDistributionGroup

1073741833

ACLableMailboxUser

1073741824

ACLableRemoteMailUser

1073741830

SyncedUSGasUDG

-2147481343

SyncedUSGasUSG

-1073739511

SyncedUSGasContact

-2147481338

ACLableSyncedUSGasContact

-1073739514

SyncedDynamicDistributionGroup

-2147482874

ACLableSyncedMailboxUser

-1073741818

SyncedMailboxUser

-2147483642

SyncedConferenceRoomMailbox

-2147481850

SyncedEquipmentMailbox

-2147481594

SyncedRemoteMailUser

-2147482106

ACLableSyncedRemoteMailUser

-1073740282

SyncedPublicFolder

-2147483130

Here is how the Recipient Type Details breaks down:

Value Name

RecipientTypeDetails (Decimal Value)

None

0

UserMailbox

1

LinkedMailbox

2

SharedMailbox

4

LegacyMailbox

8

RoomMailbox

16

EquipmentMailbox

32

MailContact

64

MailUser

128

MailUniversalDistributionGroup

256

MailNonUniversalGroup

512

MailUniversalSecurityGroup

1024

DynamicDistributionGroup

2048

PublicFolder

4096

SystemAttendantMailbox

8192

SystemMailbox

16384

MailForestContact

32768

User

65536

Contact

131072

UniversalDistributionGroup

262144

UniversalSecurityGroup

524288

NonUniversalGroup

1048576

DisabledUser

2097152

MicrosoftExchange

4194304

ArbitrationMailbox

8388608

MailboxPlan

16777216

LinkedUser

33554432

RoomList

268435456

DiscoveryMailbox

536870912

RoleGroup

1073741824

RemoteUserMailbox

2147483648

Computer

4294967296

RemoteRoomMailbox

8589934592

RemoteEquipmentMailbox

17179869184

RemoteSharedMailbox

34359738368

PublicFolderMailbox

68719476736

TeamMailbox

137438953472

RemoteTeamMailbox

274877906944

MonitoringMailbox

549755813888

GroupMailbox

1099511627776

LinkedRoomMailbox

2199023255552

AuditLogMailbox

4398046511104

RemoteGroupMailbox

8796093022208

SchedulingMailbox

17592186044416

GuestMailUser

35184372088832

AuxAuditLogMailbox

70368744177664

SupervisoryReviewPolicyMailbox

140737488355328

Here is how the Remote Recipient Types break-down (thanks to cstep for this piece):