PowerShell

PowerShell Module for AD/ ADLDS Schema modification

A couple of years ago a colleague within my company (Avanade) published a link to a GitHub project that he had just completed: https://github.com/SchneiderAndy/ADSchema

I had just finished working on a project using MIM to synchronise identities and groups from two domains into one Microsoft ADLDS instance, using the ProxyUser class to allow ADLDS to become a common authenticator for a divestment. While proving out the solution, the target ADLDS instance was trashed and rebuilt countless times. The rebuilds were time consuming and boring. With this use case in mind, I took a fork of Andy’s solution and spent a few months (off and on) to modify the module to allow its use against ADLDS, as the methods used to interact with ADLDS were often very different.

My version of the module can be found here: https://github.com/jkbryan/ADSchema, the detailed usage examples are detailed in the readme file.

If you want to give it a try, please, please test against something non-production! I will not be held responsible for any mistakes made while using the module. Test, test and test again before using it in a production environment!

New-PAMDomainConfiguration: There was no endpoint listening at http://localhost:5725/ResourceManagementService/MEX

Still suffering pain trying to get the MIM PAM lab setup on my underpowered Hyper-V System.

I was having a lot of issues with getting the New-PAMDomainConfiguration cmdlet to run successfully, so after lots of debugging; I gave up, trashed the current lab setup and started again, following the lab guide to the letter this time! Well, almost.. I only have two VM’s these are the DC’s for each domain, with everything crammed onto them.

A quick error and fix – as per the title:

New-PAMDomainConfiguration1

Issue was that the SQL service had not started, thus the Forefront Identity Manager Service had not started. Fix… start those pesky services and try again. I believe that the services are failing to start simply because of little resource (2 GB RAM only).

Now that was simple, but I’m still seeing the problems that I was seeing before; that being that when running the New-PAMDomainConfiguration after starting the services, I get the following unhelpful error:

New-PAMDomainConfiguration: The Netdom trust command returned the following error:

New-PAMDomainConfiguration2

Ah the “Blank Error” error – digging through the $error variable does not reveal anything useful. If I find a solution, I’ll be back….

I posted a question on the TechNet FIM forum:

https://social.technet.microsoft.com/Forums/en-US/be2433b4-daa6-493c-8922-684df506337d/newpamdomainconfiguration-the-netdom-trust-command-returned-the-following-error?forum=ilm2

The workaround provided by Jeff seems to have worked – well there were no errors executing the detdom commands. I have a few more bits to do to complete the lab and verify that all is working as expected.

Delegating Group Management – Using the Lithnet FIM PowerShell Module

Within my AD structure, group management is delegated within certain OU’s, I now need to replicate that functionality in the FIM portal.

The is no real way of identifying which groups should be managed by whom, except the OU within which the group currently resides.

So, to start off with I need to get the parent OU of the group into the portal:

Import the OU into the MV:

Setup an export flow for adOU into the portal.

Then, by using the Lithnet PowerShell Module, we can create all the sets and MPR’s required, below is a sample for creating one delegated “collection”. In production, my XML file is much bigger – delegating group management to around ten different groups.

Note, that you first need to create references to all users who might be given the rights to manage groups. This includes the FimServiceAdmin and FimServiceAccount – referenced by their ObjectID, the others are referenced by their AccountName. All members referenced in this section, are added to the __Set:GroupValidationBypassSet. This set is defined in the non-administrators set – not in this set – this bypasses the group validation workflow:

AllNonAdministratorsSet

Create a set of groups to be managed – the filter being the OU that the groups belong to & MembershipLocked=False

Create a set of administrators for this delegation – adding the explicit members

Then create the two MPR’s to allow the members of the administrative set to manage those groups – the first MPR allows modification (Read, Add and Remove) of the ExplicitMember attribute, while the second allows creation and deletion.

Use Import-RMConfig -File <PathToXML> -Preview -Verbose to validate your xml and see what it would do. Drop the “-Preview” to make the change

Yubikey Neo

So this is not directly relevant to FIM per se, but it falls under the kind of IdM/ Authentication umbrella, so I thought it belonged here….

In December 2014, I bought a Yubikey Neo. I wanted to see how it could be used to harden access to some sensitive “stuff”.

These are really cool devices; they are relatively inexpensive (~£36), yet provide a bunch of functionality all on one device, some of which I have not used.

The components that I did use were:

  • Yubico OTP – the One Time Passcode functionality that is present OOB – used to sign into the Yubico Forums
  • U2F – I use this for 2FA for my Google accounts and this blog – it is very simple to set up this 2FA method across multiple services. Look here for more information: https://www.yubico.com/applications/fido/
  • SmartCard (PIV) – this was the part that I was really interested in for securing stuff within the enterprise. I had recently installed a Windows PKI Infrastructure, so used that to generate trusted SmartCard Logon Certificates to install onto the devices. Look here for configuration docs: https://developers.yubico.com/yubico-piv-tool/

As with most of these things the documentation was initially difficult to read, there were various command line tools to manage different aspects of the Yubikeys, some of them had bugs at the time.

Anyway, long story short, back then I got it configured just how I wanted and used it daily ever since. However, just before Christmas, the SmartCard certificate that I had generated the previous year expired. Thus, the SmartCard functionality of the Yubikey became invalid.

I generated myself a new certificate from my CA, then came to try to remove the old certificate from one of my Yubikeys. I could not because I needed to authenticate against the device to carry out this action. The authentication string (aka password) is called the Management Key, that is (should be) changed from the default value when configuring the device. I went on the scrounge trying to find the key for this particular device, I found my old notes (command line dumps) from the previous year, there were a few management Keys within but not one for this particular device.

So, I might as well reset it, back to the docs: https://developers.yubico.com/yubico-piv-tool/YubiKey_PIV_introduction.html, in order to be able to reset the device, I first need to lock the device, by providing bad PIN and PUK values:

OK, so now I need a new management key….. The docs use dd to generate the key:

At the time, I didn’t have easy access to a Unix system to do this, but more importantly I wanted to find a way to achieve the same result in Windows, using PowerShell. This would allow me to script the whole process. Here is the script to create the management key (For info about what “{0:X2}” means, look here: http://www.powershellmagazine.com/2012/10/12/pstip-converting-numbers-to-hex/)

I have now re-written a script that I put together last year to add initialise a new or reset Yubikey (with PIV support) and add a user SmartCard certificate from a Windows CA:

O365 License Management, Using AD Groups

Previously, I wrote the following post about license management: https://365.oholics.net/office-365-licence-management/. This post relied on text files to hold the UPN of users who should have specific licenses.

I now have a new script the does that same task but uses AD groups to hold the licence entitlements. I have placed a copy of the script below.

One thing of note (a bug), that will be present in the previous script, is that of assigning a licence that is in conflict with an already applied license. This issue arose while testing this new script, notably for users who were being entitled to a Project licence.

During processing, I was seeing errors like “Conflicting Service Plans: SHAREPOINTWAC_EDU, SHAREPOINTWAC_EDU” and “Conflicting Service Plans: SHAREPOINTSTANDARD_EDU, SHAREPOINTENTERPRISE_EDU”. Where this part was present in both of the license collections – the one already applied and the project license that was to be applied.

The solution is messy, but does work.

First the “base” user licence “STANDARDWOFFPACK_FACULTY” must be removed, and then replaced by the same license, but with more disabled components – in this case EXCHANGE_S_STANDARD, SHAREPOINTSTANDARD_EDU and SHAREPOINTWAC_EDU. Once that is complete and verified, then try to apply the complete Project license.

The complete script is here:

Getting license details for your licensed O365 users

Part of the process of getting the script in the previous post working was having a record of who is licenced *now*.

This was done using the following script. Note that the commented lines must be un-commented to log the data, I am currently using this script to keep the AD groups up to date , hence the Add-ADGroupMember lines are uncommented. AD groups will soon be replacing the text files.

Office 365 Licence Management

Since introducing O365 to my organisation, there has been a steady flow of people wanting to use services within it. The licences for which have been applied on an ad-hoc basis by several global admins.

Now we are in a position to make these services more official/ production, I needed to licence those users who were not yet licensed, plus sort out the improperly licensed people.

It seems that either one of those global admins who was assigning licences or maybe self registered users were getting the Information Worker licences – e.g. STANDARDWOFFPACK_IW_STUDENT. This was not desired, so my script had to sort those out as well!

Additionally, people whose status changed from being staff to anything else needed to have any staff licence revoked and replaced with a student licence – and vice versa.

I also wanted to control who should be given those individual licences, like Office Pro Plus and Dynamics. For the moment, those entitled to these licensed are held in text files – I’m working on migrating to using AD groups instead, but for now just needed something that just works!

The script logs added and removed licences, to C:\Office365-Scripts\Licencing\LicenceManagement.txt

Error emails are based on the content of the $error variable, using a function to generate the mail body.

Here is the script:

Replacing the ADFS Service Certificate

The initial service certificate used for my ADFS service was relatively simplistic – containing only one UPN suffix.

Recently, the security team stated that they wished to start using InTune, via SCCM. Thus, I needed to enable the Workplace Join functionality on the ADFS server farm.

In order to do so, I obtained a new certificate with the additional SAN: enterpriseregistration.<MyDomain>, then I needed to replace the service certificate on the ADFS servers in the farm. This process was followed:

  1. Install new certificate on all ADFS servers in the farm
  2. Allow the ADFS service account read permissions on the private key
  3. On the Primary ADFS server, set the new service certificate
  4. Obtain the certificate thumbprint from the new certificate, e.g.: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  5. On all ADFS proxy servers – Set-WebApplicationProxySslCertificate -Thumbprint: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  6. On the Primary ADFS server – Set-AdfsSslCertificate -Thumbprint: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  7. Restart ADFS service on all servers

8. Test, by doing a federated login via portal.microsoftonline.com

Using Credential Manager to authenticate Office 365 scripts

When I initially started delving into the management of my Office 365 tenancies, I was looking for a secure way of providing a username and password, with which to authenticate (connect) to MSOL.

I didn’t particularly like the idea of putting plain text usernames and passwords into my scripts. However, shortly after getting my ADFS servers up and running, I applied the Microsoft Office 365 Federation Metadata Update Automation Installation Tool. If you look at how this works, you see that it uses Credential Manager to store the username and password. It extracts these when needed to connect to MSOL. This seemed like a nice clean solution, so I “borrowed” the methodology for most of my O365 scripts.

Take note that the Windows Credential Manager is profile specific, so if you need a service account to run some of your scheduled tasks of the like; then you need to create the credential under that profile. If you ever want to change the password of the account stored in credential manager, you can change it via the GUI, but remember that you need to do it for every profile that might use it.

So, first we need to create the credential that we want to use in our scripts:

Note line 31 – $TargetName = “LicenceManagment” – this is the label of the “Credential”, this is what is used in the subsequent scripts to get the credential.

OK, so now we have the credential stored, lets test it – I often end up using this generic connection script, when I want to have a quick look at something in MSOL:

Thus, this Generic connection script is the basis for most of my management scripts, the rest is just bolted onto the bottom.

Mail notification process continued…

After all of the previous work, defining the pieces to get the mail notifications working, I noted that I was still getting mails that had blanks for the users details – where the attributes were being referenced like [//Target/AccountName] in the email template.

I understood the “why” – the accounts had been deleted – thus they were a transition out, but the object going through the workflow no longer had any attributes! Now to find a solution….

I put a post on the Technet forums: https://social.technet.microsoft.com/Forums/en-US/b9bf96b9-ac1f-4039-889d-8063fe45058f/mail-notification-with-blank-targetaccountname?forum=ilm2, to which Brian offered some useful suggestions.

I thought that a custom workflow would be the most elegant solution and would give me a good opportunity to learn, although it might have been a little overkill to solve the issue, it would be a simple workflow. Oh, how wrong I was 🙂

I started trawling around looking for examples to get me started, mostly in C# – which I’m not particularly comfortable with! Of particular note was http://www.fimspecialist.com/fim-portal/custom-workflow-examples/ and this https://social.technet.microsoft.com/Forums/en-US/66924b6d-8331-4389-a34e-8e45ab9cc765/custom-workflow-activity?forum=ilm2, which helped with the method to get the AccountName attribute.

So, after a fair few failed attempts, with mysterious compilation errors, I think I finally have it; a workflow that takes the current request and looks for the AccountName attribute – it even builds successfully (wow)!. So lets see if just that little bit works – in debugging mode….. Oh, so I also need an AIC to be created – looking at the documentation – I try this and that, getting nowhere and frustrated…

So, then I find Carol Wapsphere’s VB.net logging example http://www.wapshere.com/missmiis/the-fim-2010-custom-logging-activity-in-vb-net. Great, lets use this as a basis. But first make sure I can get it working on its own…… Failure again…Why?? AIC?

By now I have really had enough – its not really like me to give up, but for now I’m through with this black magic! I’ll come back later to dig into this again, just not now… I need a workaround to the issue for now and I know that the PowerShell Workflow will answer it – everything is possible with PowerShell!

Over the weekend I have been mulling over what I need to do using the PowerShell Workflow (http://fimpowershellwf.codeplex.com/). Looking at the Logging example script, I see that this should be easy. So, I start playing… OK, so I have my target requestor – how do I get the attribute values from it? The documentation is very good in terms of getting going, but does not offer much in the way of examples – e.g. getting the data from the PSObject. Using Get-Member, I can see that all of the attributes that I want are present, but when I refer to them in the script, by $Target.AccountName, it appears that the returned value is $NULL when run in the PS workflow. However, I can see that this is not the case in a standalone PS window.

Eventually, I find a way of getting the data out – e.g.: $Target.Get($_).AccountName, I’m pondering over why I need to jump through the hoops to get the data, but am happy that I got there in the end. I published my initial “solution” to my original question on TechNet and Brian comes back suggesting that I don’t need to use this convoluted way of getting the data – $Target.AccountName should just work!

After a few exchanges, it seems that by not including the -OnlyBaseResources switch on the Export-FimConfig cmdlet, I am getting referentially linked objects as well as the object that I have requested. By adding this switch, I can now get the data cleanly via $Target.AccountName.

To make use of this process, I now have to modify transition out process. Delete the transition out Email Template then change the workflow, so that is uses the PowerShell workflow – with the path to each PS script for each type of OU move. The html files used previously for the move operation also need to be modified to allow them to make use of the data/attributes being assigned to variables in the script.

So, here is the script that I put together, I need a copy for each move type, plus an amended html file for each move – no big deal, just some simple search replace.

Script to send email notification only if the AccountName exists:

The Email body file is also amended as shown: