Subscribe via Email

Subscribe via RSS/JSON


Creative Commons Attribution 4.0 International License
© Rakhesh Sasidharan


Assigning and viewing NSX Security tags via PowerShell / PowerNSX

I have a bunch of VM names in a text file. I want to assign an NSX Security tag to all of them. 

To get the NSX Security tags of a bunch of VMs in a text file (so u can confirm the above worked):

These require PowerNSX BTW. 

I had to do the same for a bunch of VMs in a folder too:

Lastly, to find all VMs assigned a security tag:

PowerShell snippet to get the name of each attached monitor

Needed to create this for a colleague. Get the names of attached monitors via WMI/ PowerShell. 

The Get-WmiObject WmiMonitorID -Namespace root\wmi cmdlet returns output like this for each attached monitor:

The Name etc. is in ASCII code so we have to take the numbers, convert to [char], and join them to get the name. Here’s what it looks like. I have to remove the 0 and concatenate the rest.

So that’s what the first code snippet does. At the end of the pipeline I do a -join “;” because my colleague wanted it semi-colon separated per monitor but that’s optional. 

Bluetooth stutters? Use wireless!

I prefer Bluetooth keyboards and mice to wireless ones because that’s one less adapter worry about. Most keyboards & mouse I used so far were wireless though as that’s popular but after switching to the Mac I invested in a Bluetooth keyboard, Apple Trackpad, and a mouse. The former two work fine but the latter (mouse) isn’t perfect. It works fine mostly but I guess I am sensitive, I can notice a lag with it at times. Initially I tried increasing the sensitivity, moving away USB 3 devices and hubs so they don’t cause any interference … but nothing helped. The mouse was fine about 80% of the time but the 20% where it would stutter began driving me crazy. The issue could be the mouse, or the Bluetooth, and so I bought a Logitech MX Master 2S mouse (saw some great reviews of it) and tried it out today. 

With Bluetooth this one too was stuttering. I guess it’s the angle of my usage. I tend to keep my wrist slanted away from the MacBook so maybe the range is getting cut off? I don’t know. Good thing about the MX Master 2S (and one of the reasons I bought it) is that it comes with a wireless receiver too so I switched to that to see if it makes a difference. And yup, HUGE difference! Now the mouse works as expected. 

On that note, the MX Master 2S is a great mouse for your Mac. It’s got 7 buttons, and you can download the Logitech Options software to customize these. I already had SteerMouse but I decided to go with the Options software as that’s more customized for Logitech. You can customize these 7 buttons to do gestures etc – show launchpad, move desktop spaces, the works! A good investment. 

When I started off with the Mac I had a keyboard, trackpad, mouse, and headphones paired via Bluetooth. I switched the headphones to wired as the audio would stutter or when playing audio the trackpad or mouse would stutter. Now I moved the mouse to wireless. Hopefully the Bluetooth can handle the trackpad and keyboard, else I’ll have to connect the trackpad via cable. Sucks that Bluetooth can’t handle the large number of devices. 

Outlook auto-discover & DNS weirdness

It’s 2am and I spent the last 2-3 hours chasing a shitty problem in my home lab to which I haven’t yet found a satisfactory answer. What a waste of time (sort of)!

It all began when I enabled MAPI/HTTP on my home Exchange 2013 and noticed that Outlook (2016 & 2019) was still connecting to it via RPC/HTTP. To troubleshoot that I deleted my Outlook profile to see if a fresh auto-discovery would get it to connect using MAPI/HTTP. That ended up being a long rabbit hole!

Background: all my user accounts are of the form I have autodiscovery setup via SCP (here’s a good blog post to read if you want an overview of auto-discovery) and in the past when I launch Outlook it used to give me a prompt like this – 


– followed by this one, where I choose “Exchange” and am done. 


Today, however, I was getting prompted for a password after the first screen and when I entered the password it complained that the password was wrong. Moreover, I noticed that it was trying to connect via IMAP and picking up an external IMAP server for this domain (the domain is setup externally too with IMAP auto discovery in the form of SRV records for That didn’t make sense. All my internal clients were pointing to the internal DC for DNS, and this DC had the zone with itself so there was no reason why queries should be going to the Internet.




(Notice the That should not be happening.)

Moreover, if I did an nslookup -type=SRV from my clients they weren’t resolving the name either. How was Outlook able to resolve this then?! (I still don’t have an answer to this so don’t get your hopes up, dear reader). Clients can query the name only if they query an external DNS server but that wasn’t happening in my case. 


Here’s an article on Outlook 2016’s implementation of auto discover. It too tells me that SCP is the default mechanism for auto-discovery when Outlook discovers it’s on a domain joined machine. Starting from Outlook 2016 however, there is a special case in that if Outlook feels the account is an Office 365 enabled one it will try and auto-discover using Office 365 endpoints (typically or My domain isn’t on Office 365, but what the heck I disabled it via a registry key but no luck it still goes to IMAP. 

Why I don’t understand is why it keeps ignoring SCP. It is as if Outlook thinks I am not domain joined and is magically able to query external DNS. The Windows VM on which Outlook runs can’t query the outside world so how is Outlook doing it?

I verified the SCP end points in Exchange (this is a good article to read) and also came across this script which you can run on the client side to make it query AD for the SCP endpoint via LDAP. (I couldn’t access the blog so had to get a cached copy via Google. So I am going to copy paste the script here for my future reference. All credit to the author of the blog). 

This correctly returned my client machines’ site as well as the autodiscover URL. 

I have no idea why auto-discover was failing. My hunch at this point was that Outlook was querying DNS some other way, because of which it was thinking it is not domain joined and so all the usual auto-discovery was failing until it hit up on the Internet face IMAP auto-discovery. So what was my DNS setup like? 

All my clients were pointing to the DC via DHCP for DNS. The DNS in turn was forwarding to my OPNSense router which had Unbound DNS running on it. I verified again, from the client and DC, that I am unable to resolve the external records of I suspected OPNSense at this point so I turned off Unbound DNS to see if that impacts the auto-discovery. Sure enough, it did! Now Outlook was behaving as it used to. 

Unbound DNS was set to listen only on the servers subnet. So there was no way a query could come from my clients subnet to Unbound (my bad, I should have checked this by querying Unbound directly – too sleepy now to enable Unbound again and see what happens). I couldn’t see any other settings either so I stopped Unbound and added root hints to the DC so it can talk to the Internet directly. (Here yet another thing wasted my time. I always set DNS servers to listen on “All IP addresses” – including IPv6. With that setting my DC was unable to resolve external names using the root hints. If I disable it to listen only on IPv4, the DC is able to resolve as expected! Something in the IPv6 was causing an issue. Funnily a colleague had mentioned this in the past but I never believed him). 


That done, my clients would now talk to the DC for DNS queries (as before), and the DC would go and lookup on its own (unlike before). No more forwarder. I tried Outlook again with this setting and auto-discover correctly works. 

The issue isn’t Unbound or OPNSense. The issue is that when my DC is using a forwarder (any forwarder, even for instance) Outlook thinks it is not domain joined and it can view my external DNS records – breaking auto-discovery. I don’t know why this happens, especially considering the OS on which Outlook is running can’t resolve the external records and can in fact resolve the internal LDAP end-points correctly. Something in the way Outlook is sending DNS queries is causing it to work differently. (Or maybe I am just too sleepy and can’t think of a simple explanation now!)

Exchange 2013 Restore

I need to restore the Contacts folder for a user. I will restore it to an admin mailbox and then email the required contact to the user from there. Pretty straightforward.

1) Create a recovery DB. The recovery DB is called “RDB”. I store it on the D: drive in a folder called “Recovery”.

2) Open Services and restart the Exchange Information Store service.

3) Set the recovery DB as over-writeable.

4) I backup using DPM/ Azure Backup Server. Restore as per here.

5) Make a restore request from the recovery DB for the Contacts folder. I will restore this to a folder called Recovery in the administrator user. The switches below are for that:

The -AllowLegacyDNMismatch is required because I am restoring to a different mailbox.

6) Keep an eye on the progress via the Get-MailboxRestoreRequest cmdlet. You can get stats this way if required:

That’s it!

If I hadn’t restored to a recovery DB via DPM and brought it to a cleanly shutdown state I can follow instructions along these lines to do that.

Setting up IPsec tunnel from OPNsense at home to Azure

This is mainly based on this and this blog posts with additional inputs from my router FAQ for my router specific stuff. 

I have a virtual network in Azure with a virtual network gateway. I want a Site to Site VPN from my home to Azure so that my home VMs can talk to my Azure VMs. I don’t want to do Point to Site as I have previously done as I want all my VMs to be able to talk to Azure instead of setting up a P2S from each of them. 

My home setup consists of VMware Fusion running a bunch of VMs, one of which is OPNSense. This is my home gateway – it provides routing between my various VM subnets (I have a few) and acts as DNS resolver for the internal VMs etc. OPNSense has one interface that is bridged to my MacBook so it is not NAT’d behind the MacBook, it has an IP on the same network as the MacBook. I decided to do this as to is easier to port forward from my router to OPNSense. 

OPNSense has an internal address of On my router I port forward UDP ports 500 & 4500 to this. I also have IPSec Passthrough enabled on the router (that’s not mentioned in the previous link but I came across it elsewhere). 

My home VMs are in the address space (in which there are various subnets that OPNSense is aware of). My Azure address space is

First I created a virtual network gateway in Azure. It’s of the “VpnGw1” SKU. I enabled BGP and set the ASN to 65515 (which is the default). This gateway is in the gateway subnet and has an IP of (I am not using BGP actually, but I set this so I can start using it in future. One of the articles I link to has more instructions). 

Next I created a local network gateway with the public IP of my home router and an address space of (that of my VMs). Here too I enabled BGP settings and assigned an ASN of 65501 and set the peer address to be the internal address of my OPNSense router – 

Next I went to the virtual network gateway section and in the connections section I created a new site to site (IPsec) connection. Here I have to select the local network gateway I created above, and also create a pre shared key (make up a random passphrase – you need this later). 

That’s all on the Azure end. Then I went to OPNSense and under VPN > IPsec > Tunnel Settings I created a new phase 1 entry. 


I think most of it is default. I changed the Key Exchange to “auto” from v2. For “Remote gateway” I filled in my Azure virtual network gateway public IP. Not shown in this screenshot is the pre shared key that I put in Azure earlier. I filled the rest of it thus – 


Of particular note is the algorithms. From the OPNSense logs I noticed that these are the combinations Azure supports – 


I didn’t know this and so initially I had selected a DH key group size of 2048 and my connections were failing. From the logs I came across the above and changed it to 1024 (the 2048 is still present but it won’t get used as 1024 will be negotiated; I should remove 2048 really, forgot to do it before taking this screenshot and it doesn’t matter anyways). Then highlighted entry is the combination I chose to go with. 

After this I created a phase 2 entry. This is where I define my local and remote subnets as seen below:


I left everything else at their defaults. 


And that’s it. After that things connected and I could see a status of connected on the Azure side as well as on my OPNSense side under VPN > IPsec > Status Overview (expand the “I” in the Status column for more info). Logs can be seen under VPN > IPsec > Log File in case things don’t work out as expected. 

I don’t have any VMs in Azure but as a quick test I was able to ping my Azure gateway on its internal IP address ( from my local VMs. 

Of course a gotcha with this configuration is that when my home public IP changes (as it is a dynamic public IP) this will break. It’s not a big deal for me as I can login to Azure and enter the new public IP in the local network gateway, but I did find this blog post giving a way of automating this

[Aside] Enable ADFS Logging


  1. Enable the ADFS Tracing Logs.
  2. Enable auditing via Set-AdfsProperties -AuditLevel Verbose. Disable via Set-AdfsProperties -AuditLevel Basic.

Mail enable an existing distribution group

FET ports

FET == Front End Transport service in Exchange 2013. Is a part of the Client Access Server (CAS) role, it accepts emails. Receives emails, Sends emails. Stateless, no inspection, queueing etc. Just a simple dude!

Here are the default receive connectors on an Exchange server. 3 belong to FET, 2 to HT (Hub Transport).


HubTransport is the Transport service on the Mailbox server role. 

Here are the ports these various connectors listen on:

These connectors are stored in AD under the configuration partition. 

Screen Shot 2019 01 01 at 1 37 27 PM

FET listens on various ports:

  • Port 25 – for receiving emails from other servers. The receive connector for this is called Default Frontend <servername>. It accepts anonymous connections from external SMTP servers for the accepted domains of this server.
    • You can create additional receive connectors on port 25 if you want to accept anonymous connections for non-accepted domains too (i.e. setup an anonymous relay). See this and this for more info on how to do that. Basically you setup a new receive connector on port 25, restrict it to certain source IPs (the IPs from which you want to accept anonymous connections), and then you modify the AD security properties of the connector to allow NT AUTHORITY\ANONYMOUS LOGON to accept any recipient when sending emails. (An alternate way detailed in the same article is to set the receive connector as Externally secured). I didn’t know the receive connectors were AD objects and you could assign ACLs to it so was pleased to learn that today. :)
  •  Port 587 – for receiving emails from clients (such as IMAP4 & POP3 clients that expect an SMTP server where they can submit emails to). The receive connector for this is called Client Frontend <servername>. This port does not accept anonymous connections, clients have to authenticate.
    • To clarify for myself because I have forgotten this from my past: port 465 is for mail submission where a TLS handshake begins immediately (implicit TLS) while port 587 is where TLS starts only after the clients sends a STARTTLS verb. What this means for Exchange is that port 587 can accept TLS connections but chances are you will get a certificate error when trying to use TLS. You must therefore assign a certificate to this receive connector if you want TLS. Thanks to RFC 8314 for reminding me of port 465 vs 587 and this FastMail page for some history. 
  • Port 717 – for receiving emails from the mailbox server role. The receive connector for this is called Outbound Proxy Frontend <servername>. This is only used it a send connector has the “proxy through client access server” ticked. If this option is not ticked the Mailbox server can send external emails directly to external SMTP hosts. (Reason for doing this is that then all outgoing emails appears to come from the CAS server rather than the Mailbox Server – better from a security point of view as the CAS is what is usually Internet exposed). 

As you can see the FET is for emails from other servers or SMTP clients. It is not used when someone sends an email via Outlook MAPI for instance. This picture from the Microsoft docs on the Exchange 2013 mail flow is worth putting here for future reference. As you can see, when Outlook MAPI is used to send an email it is stored in the mailbox database and the Mailbox Transport service picks it from there. Outlook doesn’t send an email via SMTP to Exchange. 


The Mailbox server has two “mail flow” services running on it. 

  • The first of these is what we saw as HubTransport in the screenshots above. This is known as the Transport service in Exchange 2013 (though confusingly referred to by its Exchange 2010 name of Hub Transport in the GUI!) and is a stateful SMTP server – i.e. does things like categorizing etc. as in the immediate screenshot above.
  • The second of these in the Mailbox Transport service (which in turn can be thought of as two components but I am going to ignore that here) and this one’s stateless like the FET. Its role is to take mail from the mailbox database and/ or inject mail into the mailbox database. It also interfaces with the Transport service to send & receive emails. 

At this point it’s worth pointing to this older post of mine with some screenshots of these components to get a better picture of the components and flow. One more screenshot I’d like to add here is this one from the Mastering Exchange 2013 book.


The Transport service (aka HubTransport) on the Mailbox server is pretty important (not that Mailbox Transport service is any less important). The Transport service does content inspection etc and has two connectors of its own. It listens on these ports:

  • Port 2525 (if the Mailbox & CAS roles are on the same server – in this case CAS has already taken port 25 for itself) or Port 25 (if the Mailbox & CAS are on separate servers) – for many things (read on). The receive connector for this is called Default <servername>
    • This port is used to receive emails from the FET for internal mailboxes, from the Transport service of other Mailbox servers, and from the Mailbox Transport service on itself or other servers.
    • Looking at the diagram from earlier (repeated below), the three incoming arrows are what it accepts emails from.  The yellow “SMTP Receive” is the Transport listening on port 2525 or 25. It accepts emails from the FET (arrow from top), the Transport or Mailbox Transport of other servers (arrow from left), and Mailbox Transport from itself (arrow from down). 

Screen Shot 2019 01 01 at 5 40 07 PM

  • Port 465 – this is used to proxy client connections (IMAP4 & POP3 email clients) to port 587 of the FET. The receive connector for this is called Client Proxy <servername>.

To summarize, the important receive connectors to keep in mind for a typical Outlook/ Exchange environment are the 1) FET receive connector on port 25, the 2) HubTransport receive connector on port 2525 or 25. If you have IMAP4 & POP3 clients then the 3) FET receive connector on port 587 and 4) HubTransport receive connector on port 465 to matter. And lastly, if you proxy outbound connections via the CAS then the 5) outbound proxy connector on port 717 also matters. 

Badhaai Ho!

2019! Yay. 

Saw “Badhaai Ho” yesterday. Nice to see touching performances from yesteryear actors like Neena Gupta and Surekha Sikri. It’s a good story too, predictable as one would expect, but well taken with not too much drama except what you’d expect and sign up for when deciding to watch such a movie. :) 

Unforgettable moment from the movie: hospital scene when a random stranger turns to Ayushman and asks “Malayali aano?”. Got to be a mallu to get that joke, it was hilarious and totally unexpected!

Watched “Teeefa in Trouble” after that. Eugh, not that great. I am a fan of Ali Zafar and was hoping for more. It’s not a bad movie … just not great! Maya Ali is fun to watch. Predictable plot again, but well taken and so can watch. 

I seem to like one or two good movies; then encounter a dud. Again watch one or two good movies; encounter a dud. One needs a dud now and then to keep things grounded I guess. 

ADFS across trusted forests

I don’t know why there aren’t any blog posts on ADFS across trusted forests on the Interwebs. I know people are aware of it (we use it at our firm for instance) but whenever it comes to cross forest lookups I only find mention of the new ADFS 4.0 feature of adding a new LDAP claims store as described here or here. That has its advantages in that you don’t need any trust between the forests but assuming you have trust in place there’s an easier method that works in older versions of ADFS too. 

One comes across brief nod to this in posts that talk about the AlternateLoginID feature such as this. But there the emphasis is on the AlternateLoginID rather than cross lookup forests. Even on the help page for the Set-ADFSClaimsProviderTrust the -Lookupforests switch is mentioned as “specifies the forest DNS names that can be used to look up the AlternateLoginID”. 

If you have multiple forests linked together in a trust (like my previous lab examples for instance) all you need to do then is specify the AlternateLoginID to be something that is unique across both forests (UPN in my case) and give the names of the forests to -LookupForests

Here are my two claims provider trusts currently.  

Branch Office is my trusted forest with its own ADFS server. I want to change things such as I can use the Active Directory claims provider itself to query the remote forest. All we need to do is run the following on the ADFS server:

In the -LookupForests switch I specify all my forests (including the one where the ADFS server itself is). When running this cmdlet if you get an error about the LDAP Server being unavailable (I didn’t copy paste the error so I don’t have the exact text, sorry) and you see errors in the Event Logs along these lines “The Security System detected an authentication error for the server ldap/  The failure code from authentication protocol Kerberos was “The name or SID of the domain specified is inconsistent with the trust information for that domain. (0xc000019b)”” then check your name suffix routing. You might not expect anything wrong with your name suffix routing (I didn’t) but that is probably the culprit (if you Google for this error that’s all you come across anyways). In my case I had the UPN suffix in both domains and that was causing a conflict (expected) but because the UPN suffix matched one of the domains I think it was causing issues locating the DC of that domain and hence I was getting this error. I removed the conflicting UPN suffix and the cmdlet started working. 

Above I am using the UPN as my AlternateLoginID, but I can use any other attribute too as long as it is indexed and replicated to the Global Catalog (e.g. mail, employeeID).

Check out this blog post for a flowchart on the process followed when using AlternateLoginID. One thing to bear in mind (quoting from that blog post): The AlternateLoginID lookup only occurs for the following scenarios:

  • User signs in using AD FS form-based page (FBA)
  • User on rich client application signs in against username & password endpoint
  • User performs pre-authentication through Web Application Proxy (WAP)
  • User updates the corporate account password with AD FS update password page

What this means is that if Windows Integrated Authentication fails for some reason and you get a prompt to enter the username password (not the Forms Based Page username password fields mind you) and you enter the AlternateLoginID attribute & password correctly authentication will fail. But if you enter the domain\sAmAccountname format and try to authenticate it will work. This is because when WIA fails and you type in the credentials manually it does not seem to be considered as WIA, nor is it FBA, and doesn’t fall under the 4 categories above and AlternateLoginID does not get used. 

Lastly, a cool side effect of using this way of cross-forest ADFS login is that the previous problem I mentioned of ADFS across forests not working with OWA & ECP goes away. :) I am not sure why, but now when I login to OWA from organization forest to resource forest, and then try to access ECP it works fine without any change to the claims. 

Tumbbad is awesome!

I saw “Tumbbad” recently. Wasn’t aware of this movie until I came across some article on interesting Bollywood movies of 2018 and it mentioned “Andhadhun”, “Tumbbad”, “Stree”, and others. 

I had seen “Andhadhun” last week (forgot to blog about it, damn!) so I gave “Tumbbad” a shot. It’s a horror movie, and very well taken at that. It’s not horror based on special effects or just trying to be creepy by sudden appearances etc. There’s a story and they have taken it well. It’s a simple story and one that says with you for a while. Definitely watch this movie if you haven’t yet! 

Might as well talk about “Andhadhun” here. This is a Sriram Raghavan movie (nothing more needs to be said; except for “Agent Vinod” and “Badlapur” (which wasn’t as gory as I hoped it would be) I have been a huge fan of all his movies (“Johnny Gaddar” being my favorite, and now “Andhadhun”). Starring Ayushman Khurrana as a blind pianist who happens to witness a murder, this is every bit a Sriram Raghavan movie as his other best work. To top things you have some amazing music by Amit Trivedi both in terms of songs and background music (the piano plays a huge role in this movie). Watch this if you are a fan of Sriram Raghavan movies or like stuff like “Fargo” – you won’t regret it!

I also saw “Stree”, which was fine. It’s a fun horror flick which is neither too much fun nor too much horror. Would have been better if it was more horror than fun, but well … can’t do much now. This was the weakest of the three movies.  Except for one bit where they make fun of the ghost regarding its IQ and obedience etc., there is nothing too memorable about this movie. 

Poirot, unpacked

Jeez I had high hopes for “The ABC Murders”. It was one of my favorite Poirot stories and well John Malkovich is playing Poirot so it must be exciting right?


All of Poirot’s backstories and mannerisms and character are removed. This is a Poirot TV show the way “Elementary” is a Sherlock Holmes TV show. You don’t really want to see it!

This Poirot has a goatee! *horror* No mustache, can you believe that! He starts off coloring his mustaches black, which I think the “real” Poirot too used to do… but this one has the colors dripping off his face. He is sad, a lost cause. Cops hate him, he has no purpose. There’s a lot of flashbacks to some mysterious and sad past… which turns out be even more disappointing as guess what this Poirot wasn’t even a celebrated Belgian cop! Jeez.

The murders and plot are faithful to the book but it’s not much fun to watch. Everything’s so sad and gloomy. Poirot doesn’t even use his “little gray cells” anywhere. The ABC killer is kind of given to him in his lap. And there’s no explanation given behind how he found the actual murdered either. Eugh!

Of course, watch it coz anyone would be curious to see it considering it’s Poirot. But don’t expect much. Maybe go listen to a Poirot audiobook to cleanse yourself after this! (After watching an episode of “Elementary” I went back and re-watched an episode of “Sherlock” just to forget “Elementary”).

I liked something Poirot says in the end. We have a tendency to characterize the current age as dark or more evil that the olden times. That’s not really true. There was a lot of cruelty in the past too. In fact I was reading a book “1000 years of annoying the French” and also recently I visited Tbilisi, Georgia and was reading about their history… there was a lot more war and violence in the past. There is a lot of it now too but saying that the present is worse than the past is just romanticizing the past. There’s always been evil in the world – it’s Humans. We are just bad and wicked. (And this is me channeling a lot of “Westworld” too into everything else! :)).

Speaking of TV shows checkout “Black Mirror: Bandersnatch” if you get a a chance. Good stuff! Or if you want murder mysteries set in cold and lonely country check out “Shetland”. Excellent stuff!

ADFS with Exchange OWA & ECP (contd.)

This is a continuation to my post from yesterday

While OWA works fine following my post yesterday, I learnt today that ECP does not work for users in the second domain. (To use correct terminology, users in the resource forest are able to login via ADFS and access both OWA & ECP but users in the organization forest are only able to access OWA. With ECP they get an error as below). 


Yeah, sucks!

With some trial and error here’s what I learnt:

  • ECP expects the SID passed along to be that of the disabled account in the resource forest (i.e. where Exchange & ADFS are hosted). Since I am passing along the SID from the organization forest it is denying access. 
  • OWA on the other hand expects the SID passed along to be that of the active account in the organization forest (which is what we are currently passing). If one tries to make ECP happy and thus somehow pass the SID of the disabled account in the resource forest OWA complains as below. 

Screen Shot 2018 12 29 at 12 49 19 PM

I managed to work around this a bit. It is not a complete fix and I wouldn’t implement this in a production environment, but since my intention here is more to pick up ADFS than anything else I am happy I came up with this workaround. 

First off I changed my second ADFS server (the one in the organization forest) to not pass along all claims to the relying party trust with the resource forest. This is not really needed, but I had to do this for one more change I wanted to implement and figured it’s best to keep a control on the claims I pass along. As I alluded to in another post from today you can end up with duplicate claims if you pass along all claims and make changes along the way. Better to be picky. Anyways, on the second ADFS server I decided to pass along just 4 claims:


At the risk of digressing, the first claim is why I initially decided to stop passing along all claims. I have admin accounts for myself with the same username in both forests, but differing UPNs, and I wanted it to be such that when I visit OWA or ECP with the admin account of the organization forest I am signed in to OWA or ECP of the admin account of the resource forest. That is, when I sign in as (organization forest; this account has no mailbox or Exchange rights) ADFS will tell Exchange that this is actually and let me login as the latter. That’s the point of ADFS and claims and all that after all – Exchange doesn’t do any authentication, it simply listens to what the ADFS server tells and I can do all this fun stuff on the ADFS side. 

Thus I created a claim rule like this:

It takes an incoming UPN claim, does a regex replace to substitute with Easy peasy. Exchange is none the wiser and thus lets me login as and access the mailbox & ECP of 

Going back to the original issue. I thus have 4 claims as above. 

The replying party trust from the ADFS server in the resource forest to OWA works fine as it is happy with the SID it gets from the organization forest. What. I need is a way to translate the SID of the organization forest to a SID in the resource forest, and pass that to the ECP trust. I don’t need to translate SID -> SID as such; what I really need to do is lookup the account name I am getting from the organization forest and use that to find the SID in the resource forest. When I create the linked mailbox in the resource forest I use the same username as in the organization forest so what I have to do is extract this username from the incoming claims and do a lookup using that. So far so good?

To do this I removed the claim rule on the ECP relying party trust that was passing through SID. (I let the UPN one stay as it is as that’s fine).

Then I added a custom rule like this:

Sanitize Windows account name

This takes an incoming windowsaccountname claim and makes a new claim (note, I add not issue – so this claim isn’t output ever) called “” (just a dummy URI I made up, doesn’t matter) and the value of this claim is the incoming windowsaccountaname but with the domain name replaced (i.e. remove the domain name of the organization forest, replace with the domain name of the resource forest). 

Now I added another custom rule:

Lookup SID

This one takes the claim I created above (the windowsaccountname with the domain name changed) and queries AD to find the objectSID attribute of this user account. This gives me the SID of this account in the resource forest. I now return it as a primarysid claim. 

To recap here is what I have:


Do this and now ECP works via ADFS! :) Unfortunately if you now try to go to OWA it fails with the error I was getting earlier. :(


The problem here is that both OWA and ECP are in the same domain https://exchange.fqdn/ and so when I switch from OWA to ECP or vice versa I don’t hit ADFS again to re-authenticate. Since my browser already has a previously signed in session’s cookie it tries to access the new URL … and fails! And this is where I hit upon a wall and couldn’t proceed further. I figure if there’s some way to make the browser re-authenticate I can make it go to ADFS again … but I don’t know how to do that. I fiddled around with the cookie settings in IIS on the CAS server but didn’t make any progress. Exchange doesn’t let you use different URLs for OWA and ECP so there’s no way to use a different domain for either these and thus bypass cookies either. Am stuck. 

So that’s it. If anyone comes across this problem and has a better idea I’d be interested in hearing. :)

Update: A workaround.

Random ADFS notes

(Nothing new here. I was taking notes when reading up while troubleshooting an issue). 

All incoming rules can be thought of as being stored in an input rules set. 

All the claim rules are in a claim rule set. 

All rules in the claim rule set share the same input rules set. Each claim rule can also add to the shared input claim set, which can be used by subsequent rules. 

The claims created from claim rules are stored in an output claim set. This is initially empty, and is populated as the rules are processed. The claims in the output claim set are what is output when execution completes. 

Claim rules are processed top to bottom as per the list. 

Claim rules are of the format Condition statement => issuance statement;

The output of a claim rule can be to either both the input & output claim set, or only to the input claim set. If the issuance statement has an add statement it is to the input claim set only; if it has an issue statement it is to both. 

Condition syntax examples here. Key takeaways:

  • You can add or issue claims as mentioned earlier. 
  • In either case you can have Normal issuance statements that (a) creates a copy of an existing claim to the output set (am not sure how this works, I can’t think of an example) or (b) creates a new claim based on values in the input claim set (these should have the claim type specified for the new claim). 
  • You can also have Attribute Store issuance statements. In a single issuance statement you can create multiple claim types or multiple claims for a given type. The attribute store will have a query syntax. See here for examples. 
  • Both condition and issuance statements make use of expressions. 
  • Regex too is supported
  • Here are some of the claim properties available: type, value, issuer, originalissuer, valuetype. 
  • Apart from matching on == (equals, case sensitive) one can also match on != (not equals, case sensitive), =~ (regex match, case sensitive), and !~ (regex non match, case sensitive). Add a (i) to make it non case sensitive. 

It is important to remember that you can’t discard claims. As in, if the input set has a claim A and you do some modifications (transforms) to it, then both claim A and the modified claim A are passed on. This doesn’t make a 100% sense to me because I get the impression from the EXISTS function that you can discard claims. I think that applies more to temporary claims you create via the add statement.

(Update: I remembered later what I was trying to convey here. Say you have a claim rule that passes all incoming claims. Then you have other claim rules that maybe modifies one of these claims. You would think that this being a pipeline only the modified claim will be passed out, the original claim will stay as it is. But nope. Because the first claim rule was issuing all incoming claims the original claim too is passed along with the modified claim. Thus it is (a) better to not blindly pass all incoming claims and (b) if you want to make changes to an incoming claim don’t issue it, rather add it, modify, and then issue. )

Some more links: