Gist

Contains GitHub Gists

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:

File server migration script with case statement

Here is the script used to migrate the clients from the old servers to the new domain based DFS namespace, note that from_srv and to_srv need to be amended and the case statement needs to be constructed based on the content of the Drive Mapping script output.

File server migration – Drive Mapping Script

A long time before planning a file server migration, I thought that it would be interesting to see which drives were mapped by our users.

We do not use a login script or GPO Preferences to do this and there is a long history of “Stuff” on the old servers.

Initially, it was down to help the helpdesk staff to re-map drives on new machines; where the user didn’t know where the target was – it was just their J drive….

Coming back to the file server migration, the historical data in this file was invaluable.

By comparing the drive mapping data with the shares defined on the target server, a list of share names and their long path was produced. This list is then used to construct the case statement within the server migration/ re-mapping script.

I’ll publish the drive-mapping script here now, as it was easy to sanitise. I’ll provide the re-mapping and rollback scripts separately.

Note that this script must be run as a Logon script in the user part of a GPO. Additionally, the target folder is a very open hidden share.

Exchange Mailbox Delegation

This is another of my old, but nice scripts. There was some discussion at the time about how different Exchange team people, who work at different geographical sites, were dealing with mailbox delegation. There was no consistency.

I read at the time about using EWS for Exchange management – notably this: http://gsexdev.blogspot.com/2009/04/add-delegates-to-mailbox-with.html. I wrapped that method in a bit more PowerShell to provide a consistent, simple to use interface for the Exchange team members.

Note that this script runs repeatedly (up to 60 times – 30 minutes) until it sees that the calendar permissions are set correctly. This was introduced to allow permissions to be set when our exchange infrastructure had been failed over to our other main site – a rare occurrence. The replication interval between those sites is set to 15 minutes. Hence, it should have successfully completed by 30 minutes or something more fundamental has gone wrong!

Creating a professional looking “Legal Text”

So a few years ago, our Security group asked us to implement a Legal warning on all Windows clients.

The simple way of doing ths is to just add the Title and Text to the following GPO settings:

Computer Configuration/Windows Settings/Local Policies/Security Options –

  • Interactive logon: Message title for users attempting to log on
  • Interactive logon: Message text for users attempting to log on

However, these settings provide no layout options whatsoever. To try to force some semblance of a layout, you need to introduce a character (we used *) at the beginning of each line then add spaces to get an indent. Adding carriage returns in the GPO has no effect! You could just plop the text in as one long line…. Either way it looks crap!

We also have some display screens scattered about that auto-logon. These machines has to be excluded from getting the legal notice, otherwise they would not auto-logon. The initial solution was to just create another OU for these machines to exclude them from receiving the policy settings. This is simple but messy, you forget to put them (pre-staged) in the right place before they are added to the domain, so you then need to trawl through the registry removing the settings….

I was looking for an alternative and found this article on the scripting guys website:

http://blogs.technet.com/heyscriptingguy/archive/2005/01/17/how-can-i-change-the-legal-warning-message-using-a-script.aspx

I used this as the basis for the script below. My version is applied at the root of the domain as a computer start-up script in a “Base” GPO. This way every client gets the legal text (except DC’s – the script is also applied to the DC’s separately).

Those auto-logon machines are handled automatically. A security group in the domain contains the computer accounts for those machines that you don’t want to get the legal text. If the computer account is in that group, the script ensures that the legal text is not set, if the machine already has the legal text and is then added to the group, the legal text is removed automagically!

Here is the script:

An update on Using Ryan Newington’s PowerShell Module to create a Mail Notification process

OK, so although all the XML definitions worked fine and the objects were created, the differentiator between a New User and an Existing User moving into a Department was a little poor.

The new user email notification was configured to use an attribute that would make it clear to the reader of the mail if it was a new or existing person. However, by the time this attribute had reached the portal (for a new user), the mail had already been sent with a blank attribute referenced…. Not good!

So a little re-think…. I need another set of Sets to handle new versus existing people for each of those groups of people who want to know!

The existing Set: OU=Blah, was used for both new and existing people where a Transition In is a New User or a user moving into that department. This one will now be used only for New Accounts only. A Transition Out was a person leaving that Department

A new Set was defined: OU=Blah AND where Portal CreationDate date is prior to Today – this will handle Existing users moving into or out of a department. Urgh, but that means that I need move in and out MPR’s, WF’s and templates, plus HTML and XOML. I am not provided Employee Start date from HR, so cannot use that.

Using the PowerShell Module, this is a little easier, but what started as just a re-hack of my original XML file turned into a slight re-design (tidy up, fixing some capitalisation (to allow for easier search/ replace) and better layout for readability) of the XML,

The existing Move MPR, WF and Template are re-purposed to become the ‘Active’ User move in (New User), then another series are created for Existing User move in and out (Movers). I also added another recipient for the initial period of testing the notifications – the real recipients will be added once I see that all is working as expected…

“—” is used as the search criteria and replaced with the relevant Department acronym – for me this joins everything up! Note that each template, once fixed, should be within the Lithnet wrapper:

The template job list is as follows:

And with slight modified XOML to match the XML, those being the references to recipients. which now has two references and the Email Template reference has its reference made to match the ID for that template in the XML, e.g.(showing “—” where the Department acronym should be) :

Using Ryan Newington’s PowerShell Module to create a Mail Notification process

One of the things that I had to bear in mind for my FIM implementation was that the current legacy code provides email notifications of changes made. Due to the nature/ structure of the organisation, the different groups only want to know about changes to their own users.

So, when initially thinking about what people are currently informed about, and then the number of MPR’s, Workflows, Sets and Mail templates required to duplicate that functionality – I thought “no way!” It would be unmanageable. In the end and after discussion with the recipients of those mails, I got to a manageable number of things that those people really wanted to know about. These are:

  • A new user starting (a real new person), or a person who has moved horizontally within the organisation – they have moved INTO that department.
  • A user in their department becoming disabled
  • A user in their department becoming deleted
  • A user moving OUT of their department

So, I’m down to 4 things, but I have 9 different groups to inform.- So I have 36 Templates, 36 Workflows, 27 Sets and 36 MPR’s to define…..Even if I had a minion, I wouldn’t make them do that manually….

So, during Ryan’s presentation to the FIM User Group, I noted that he had introduced the ability to import these object by providing an XML file that defined them.

Using the examples from here https://lithnetrma.codeplex.com/wikipage?title=configuration%20management&referringTitle=Home and a bit of syntax pain, I ended up with the XML file below – note that this only does the “stuff” for one one those groups – my production XML file has all of this 8 more times – with pointers to alternate XOML and html files.

Load the Module, then check the validity of the XML file by running:

Import-RMConfig -File .\YourXmlFile.xml -Preview -Verbose

If all looks OK, run the command again without the Preview & Verbose switches.

My initial runs ran into errors due to the way that the employeeEndDate plus 180 days filter was being passed to the FIM service. Ryan has rapidly fixed and produced new versions to resolve these problems.

The great thing about this method, is that by using xmlref pointers, everything just joins up, resulting in a consistent set of objects that reference each other.

Note that the line:

Is used to provide a reference to the mail recipient, more recipients could be added, using the same structure, but a different id. Other pre-existing object references could also be added as appropriate.

So to summarise what is defined in the XML file:

  • 4 Email templates – Add, Disable, Delete & Move – each with a corresponding and each slightly different html file
  • 4 Workflows – Add, Disable, Delete & Move – each with a corresponding and each slightly different XOML file
  • 3 Sets – User in OU=Blah, User in OU=Blah AND whose Status=Disabled, User in OU=Blah whose end date has passed, plus 180 days
  • 4 MPR’s – Add, Disable, Delete & Move – all are transition in, except for the Move MPR, which is a transition out.

An example of the XOML and html:

Removing an Attribute from the Portal

A few weeks ago, I created a new attribute in the portal called adOU. This attribute contained the Active Directory OU of a user and was defined in code from the HR database input – that’s where the OU definitions are defined…..

I planned to use the attribute to define Sets containing the users whose accounts resided in those OU’s. So, after creating and populating that attribute, I started looking at the Set’s Workflows, MPR’s and Email templates that I’d require to make use of that new attribute – these items were to be used to send email notifications.

When I got to the point of creating the Sets, I noted that I could not choose the adOU attribute as a criteria. I checked the relevant MPR’s, Admin filter etc., all looked OK. Then I realised that when I created the new attribute, I had configured it as an un-indexed string. Thus, this was the reason that I could not use it in my Set definition.

So, off I go trying to delete the binding and attribute, always fails – after doing the few normal bits that I remember that I need to do beforehand – I have been here a few times before!

So, its about time that I documented all of the steps, to save me and maybe others the pain in the future.

  1. Delete the attribute mapping in the FIMMA:

AttributeMapping

2. Un-tick the attribute in the attribute chooser in the FIMMA

.Attribute

3. Remove any references to the attribute in any workflows, MPR’s, Sets, mail templates etc..Run an Export policy script like the following, then look for references (e.g. “[//Target/adOU]”) to the attribute in the resulting xml file:

4. Clear the attribute from all users. Previously, I have used an MPR and workflow to to this, but in this case, I found it unreliable. So turned to the LithnetRMA PowerShell module (https://lithnetrma.codeplex.com/):

5. Finally, delete the binding and then the attribute – they should go now – if not something has been missed.

6. Refresh the FIMMA schema

Now in my case, I then re-created the attribute – as an Indexed String, and then the Binding. Then refreshed the FIMMA Schema again, added the attribute to the FIMMA picker, recreated the FIMMA flow, reset the MPR’s (to allow the attribute to be managed) and Admin filter permissions. Then run the export to get the data back into the portal. The Set criteria now contains the option to use adOU.

Defining a Unique Email Address and Validating Mail Suffix

In addition to creating a valid and unique email address – as defined here: https://blog.oholics.net/defining-a-unique-email-address/

I also need to detect where those addresses might need to be changed. The AD and Exchange infrastructure supports a number of different tenant organisations, each with their own needs. There is regular horizontal movement of users between these organisations.

So I have added to my code to define a unique email address – the additional content starts at Line 72 – statement “If mventry.Item(“mail”).IsPresent Then“. Note that attributes are set on the import from HR to define who is entitled to an MBX and those who should just be mail enabled. The current code just logs out those things for action, but I have also included making these events throw an exception to the Sync Engine.

It was interesting to see just how many people are not really entitled to a mailbox, but who have one anyway!

Full WBADMIN backup script

Script to do a full backup using WBADMIN to a local staging drive and then copy the resulting files to another server. The clean-up script (called within my script) can be found here:https://gallery.technet.microsoft.com/scriptcenter/Delete-files-older-than-x-13b29c09

This resulting backup files from this script allows me to do a bare metal restore of a virtual domain controller within ~30 minutes. This assumes complete meltdown of your domain – catastrophic failure, schema issues, compromise, etc. – where you need to restore it from scratch – this is a last resort action!. Once restoration is complete move onto the rest of the recovery process. Of course this script will also do nicely for just backing up all critical drives and registry on any other server or client!