PowerShell Attribute Store for AD FS 2.0
Saturday, November 19, 2011 at 04:41PM *WARNING: Academic exercise only – I’m not sure how this would scale in production*
Download the PowerShell Attribute Store
So I was at an event last week and a buddy of mine told me that he had an intern create an attribute store for AD FS that would provision an AD account if one didn’t exist. I got to thinking about this, and I thought why stop at provisioning accounts? Why not have an attribute store that you can use to call any PowerShell script that you want and return the results as strings that you can use in claims.
So I went back and wrote it up and decided to share it with everyone. Feel free to download the attribute store and try it out. It’s really simple – here’s how it works:
- Create the PowerShell Attribute Store in AD FS
- Create the PowerShell script. In the script, pass the string that you want to give back to AD FS with the Write-Output cmdlet
- Create a claim rule that calls the attribute stor. Pass in a query string in the following format:
FULL_PATH_OF_SCRIPT;SCRIPT_PARAMETERS
I’ll illustrate how to use the PowerShell Attribute Store with an example. In this example, I’m going to get the size of the user’s home directory as a claim.
Example: Getting the User’s Home Directory Size as a Claim
Step 1: Install the PowerShell Attribute Store DLL
Download the PowerShell Attribute Store and copy the file PshAttrStore.dll into your AD FS installation folder. For example, C:\Program Files\Active Directory Federation Services 2.0
Step 2: Create the PowerShell Attribute Store
Create the PowerShell Attribute store as a custom attribute store in AD FS. In this example, I called it PshAttrStore. The class name is Class1 (I know it’s lazy, but I literally just threw it together in a few minutes), so use the following string for the class name in the custom attribute store: PshAttrStore.Class1, PshAttrStore
Step 3: Set AD FS Account Permissions
Give the AD FS Service Account permissions to run the script. I just added the AD FS Service Account to the local Administrators group on the AD FS server. Ideally, you would want to take the time to figure out what permissions it actually needs in order to execute PowerShell scripts, but I didn’t take the time to do that. If anyone figures it out, post it as a comment and I’ll update this post with the information.
Step 4: Create Your PowerShell Script
For this example, I’m going to use a script that takes in the name of a folder and returns the size of it as a claim. When returning the data back to AD FS, you have to use the Write-Output command at the end of the script. Here’s my example script:
|
## GetFolderSize.ps1 ## ------------------- ## A sample script to return the size of the folder passed into the ## script as an argument
## Get the name of the folder as the first argument in the script $directory = $args[0];
## Get the combined size of all of the items in the folder $size = Get-ChildItem $directory | Measure-Object -Property Length –Sum
## Calculate the size in MB and format the size to 2 decimal places $displayedSize = "{0:N2}" -f ($size.sum / 1MB) + " MB"
## Return the size of the folder back to AD FS Write-Output $displayedSize |
Step 5: Create the Claim Rule
I’m going to use my GetFolderSize.ps1 script to get the size of the user’s home directory. To do this, I’ll need two claim rules:
- Claim Rule 1: Get the path of the user’s home directory by querying the homeDirectory attribute in Active Directory
- Claim Rule 2: Call the GetFolderSize.ps1 script and pass in the home directory path that I got in the first claim rule
Here is what the claim rules for this look like
Claim Rule 1: Get Home Directory Path

Claim Rule 2: Get Home Directory Size

Step 6: Testing It Out
To test this, I’m going to use ClaimGrabber, which is a tool that I wrote to assist in claim rule authoring. I’m using a beta version of ClaimGrabber in this post, which I’ll finish writing and post shortly.
You’ll notice in the ClaimGrabber output (below) that we are passing the application a claim called http://eag.demo/directorySize with a value of 14.77 MB. This claim is what we got back from the PS1 script!

Other Uses and Feedback
I thought this was an interesting idea to try out and I’m rather surprised how well it worked. The results are pretty quick – there’s no noticeable delay when the user logs in, but I’m only running a simple script. I could see scenarios where you might want to use this to run some complex scripts. There are a ton of scenarios that you could use this for. Here are some that I could think of off the top of my head:
- An easy way to do custom attribute stores without having to write a compiled .NET DLL
- Auto-provision user accounts based on the claims
- Kick off a FIM sync script for on-demand provisioning
- Log some data about the user to an alternate audit log
I’m really interested to hear some feedback on this – in particular:
- Would something like this be useful to deploy in production?
- What other scenarios / scripts could you use this for?
ADFS v2,
PowerShell 

Reader Comments (6)
This is a great idea, but I'm wondering if you have any ideas for how the PowerShell commands could be restricted so that this isn't vulnerable to query string manipulation. Or might there be other, better approaches to mitigating those risks?
Thanks, Tristan -
This wouldn't actually be vulnerable to a query string manipulation attack because the data that you're feeding into the PowerShell script is coming from a trusted claim, not the end user directly. If you are receiving the claims that you are feeding into the script from an external IdP, then you would definitely want to filter them with the standard practices that we recommend using in other scenarios as well.
If I were to implement this in production, there are a couple of things I would do:
- Lock down the AD FS service account such that it can only access the things that the script actually needs access to
- Run some filtering logic on incoming claims from external IdPs (we always recommend this anyway - in fact, we warn you in AD FS when you use the passthrough template on an external IdP)
- Add some performance counters into my script so I can have some view into the execution of the scripts
//Ken
Hmm, Powershell - cool!
I wrote a custom attribute store for Forefront Identity Manager 2010 about a year ago and placed is at CodePlex (http://fimattributestore.codeplex.com/). Pretty soon afterwards there was a discussion on the CodePlex website if it could be a good idea extending it to do provisioning and since I thought this could be a nice to have feature I contacted Dominic Baier(http://www.leastprivilege.com - MVP, author of "A Guide to Claims-Based Identity and Access Control" (http://msdn.microsoft.com/en-us/library/ff423674.aspx) and well known profile in the claims world) with this idea. His comment was pretty clear:
"well – for me this sounds like a clear violation of separation of concerns. An attribute store has one clear mission: “fetch attributes”. Not provisioning users."
Having a Powershell attribute store is a great idea but it's not such a great idea using it for provisioning and how would you handle deprovisioning!?
//Henrik
Hi Henrik -
I've actually used your FIM Attribute Store - it's a great idea and partially inspired a really interesting solution that myself, Heath Aubin, Brad Turner, and Chris Calderon are working on with some of our customers.
I'm familiar with Dominic's blog and he's an awesome MVP - always full of great information! The intent of the custom attribute store was to provide some form of complex claims transformation that couldn't be done with the limitations of the claim rule language. Whenever I post a blog like this where I talk about doing something that we (Microsoft) would consider "unsupported", I shoot my friends in the product group a note to let them know that this is out there. I've only had one situation where we discovered something really interesting, but one of the devs specifically asked me to not blog about it. :) I'm all for stretching the technologies to another level - that's how we make products better. Whether or not we'll support it is another story altogether. I'll give an example from CSS... In the claim rule language, there is no way to do a case conversion of a string. There's no method for something like ToUpper() or ToLower(). So one of our CSS guys wrote an attribute store that would do the conversion and return the result. This is something that customers really need and we've seen it quite a few times. This is also something that the claim rule language should handle natively. But I think it's completely acceptable to do this a custom attribute store for now.
I think using an attribute store to provision users is an interesting idea, and I think there are cases where it might be acceptable. The one that is top of mind is where I'm publishing a Kerberos application and want to use something like UAG to do SAML to Kerberos delegation. In order to do delegation, I need an account in AD, so you can have the attribute store spin up an account with a random ID and password and attach the nameidentifer from incoming token to it. If you did it at the attribute store then you would ensure that the object existed on at least one DC before the token is returned back to UAG to do KCD with it. You would just have to make sure that you scope UAG to use the same DC that you are provisioning users into. De-provisioning is another story, but this scenario could be a good case for FIM to deprovision those objects after some static time period. I probably wouldn't want to do deprovisioning with an attribute store - it would just be too complex to write the business logic piece to ensure that you don't delete something that shouldn't be deleted.
Another scenario that I think would even be more interesting would be to use the PowerShell attribute store to kick off the FIM sync cycle. Rather than AD FS do the provisioning directly, submit it as a request to FIM and then kick off sync. The user's logon might take some time in this case, and you'd have to account for that, but there could be scenarios where this might be acceptable.
Good stuff! By the way - I worked on the 2nd edition of the Claims Based Guide to Identity - make sure you read this one, too - we've added SharePoint 2010 and Azure to it! http://msdn.microsoft.com/en-us/library/ff423674.aspx
//Ken
Hi Ken!
I've tried earlier to make another answer but maybe your blog is moderated (probably is) but I'll try again anyway...
I really appreciate you published the idea about a Powershell Attribute Store and even that you told your writers it could be used for provisioning users or profiles. Just like you I think publishing "unsupported" stuff drives technology but I think you should have been a little bit clearer around the problem using it for provisioning. Anyhow, I've made my statement and hope your readers find this interesting an that they'll reach my warning about it.
BTW: Have you tried this:
c:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"]
=> issue(store = "SQL", types = ("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"),
query = "SELECT UPPER({0})", param = c.Value);
...And you of course make your own advanced functions in SQL like this (not perfect in date conversion though):
CREATE FUNCTION IsOver21 ( @BirthDate nvarchar(10) ) RETURNS nvarchar(3)
BEGIN
DECLARE @Age int, @ReturnValue nvarchar(3)
SET @Age = DATEDIFF(year, CONVERT(DATETIME,@BirthDate,20), GETDATE())
IF @Age > 21
SET @ReturnValue = 'Yes'
ELSE
SET @ReturnValue = 'No'
RETURN(@ReturnValue)
END
Now I know... I missed the captcha...