Setting up Office 365 Directory Synchronization and filtering out users after the effect

Posted 21 May 2012, 17:33 | by | | Perma-link

If you're considering moving to Office 365, you've probably been looking into the options for Directory Synchronisation. If your AD is anything like ours, you'll have a number of accounts for services, ex-staff, contractors, etc. that you don't really want synchronised up to Office 365.

By default there's no control over the filtering of accounts within the Directory Sync Configuration tool, and the content on setting this up has been "coming soon" for over 6 months, which is a shame, however, when you run the Office 365 Deployment Readiness Tool you'll see the following line in the reports:

Filters were applied to obtain the above object counts for an Office 365 deployment.

So clearly these filters are configured somewhere - but where?

Hunting around on the web, I've found a very useful post for the initial setup scenario from credera: Filtering Users in the Office 365 Directory Synchronization Tool where they talk about using the UI based on Forefront Identity Manager (FIM 2010) - and suggest you run this before DirSync runs. I failed to realise the implication of one aspect of this: Even if you clear the "Synchroize directories now" so DirSync doesn't force the update, you've started the service and the 3 hour timer - so don't start this just before you go home for the weekend, otherwise you'll end up with all your accounts online like I did.

So how do you implement filtering after you've done initial import? Well, it's not too painful once you've looked around at the systems.

Start by firing up the Synchronization Service Manager through using the miisclient.exe executable found deep in the Sync Service's UIShell folder, and switch to the "Management Agents" pane. Click on the "SourceAD" Management Agent line, and select Properties.
View Management Agent Properties

Then select the "Configure Connector Filter" (apparently you can also do things with the Directory Partitions - your milage may vary), select "user", and create a "New..." rule:
Configure Connector Filter

As I'm only interested in importing users from our "Staff" organizational unit, and groups from our "Company_UserGroups" OU, I set up one filter with the following rules:
Add new filter

"<dn>" "Does not contain" "OU=Staff"
"<dn>" "Does not contain" "OU=Company_UserGroups"

Ok out of the dialogs and return to the "Operations" page. You now need to perform a Full synchronisation to remove the filtered out users:

From the Actions menu, select "Run..."
Actions | Run...

Ensure that "SourceAD" Management Agent is selected in the top dropdown, then select "Full Import Full Sync" from the list of Run profiles, and press "OK".
Full Import Full Sync report

Once that operation shows has a status of "success", select "Run..." again, and this time switch to the "TargetWebService" management agent, and choose the "Full Confirming Import" run profile, and press "OK".
Full Confirming Import report

Once that operation also shows a status of "success", you'll want to run the "Export" profile for the "TargetWebService" management agent.
Export report

As you can see, after each run you should see confirmation of deleted accounts in the reports.

To confirm that they've really gone away, you can then fire up forced run of the standard sync using the powershell command Start-OnlineCoexistenceSync if you run the DirSyncConfigShell powershell script from the root of the DirSync install folder, or by re-running the Directory Sync Configuration Tool.

Just deleting the users from Office 365 using the Remove-MsolUser command obviously didn't work as they were just recreated again with the next diffential sync.

I also found that the event log will contain warnings that your configuration has changed and you need to perform a full sync for the changes to take effect:

The management agent "SourceAD" completed run profile "Delta Import Delta Sync" with a delta import or delta synchronization step type. The rules configuration has changed since the last full synchronization.
User Action
To ensure the updated rules are applied to all objects, a run with step type of full synchronization should be completed.

Filed under: Office365, PowerShell, Tools

Interesting finds around PowerShell Mandatory Parameters

Posted 20 June 2011, 15:47 | by | | Perma-link

I noticed an interesting thing today while attempting to make some parameters on a PowerShell script required.

As I'm just starting to get the hang of PowerShell, you'll have to bear with my script-kiddie tendencies, however, here's the background:

I'm creating a script that will take the following parameters (can you tell I'm still working with TFS?):

  • [string] WorkItemType
  • [string] ProjectsToUse
  • [switch] ExportWitd

I wanted to make the WorkItemType parameter required, and searching around the internet led me to the following code:

[string] $WorkItemType = $(throw 'workItemType is required')

Which does indeed "work" if you're happy with exceptions being thrown if you don't set it:

workItemType is required
At C:\Scripts\UpdateTFSWorItems.ps1:17 char:37
+     [string] $WorkItemType = $(throw <<<<  "workItemType is required"),
    + CategoryInfo          : OperationStopped: (workItemType is required:String) [], RuntimeException
    + FullyQualifiedErrorId : workItemType is required

And it also doesn't help if more than one parameter is required (you only get the first error), and get-help doesn't help:

PS C:\Scripts> get-help .\UpdateTFSWorItems.ps1
UpdateTFSWorItems.ps1 [[-WorkItemType] <String>] [[-ProjectsToUse] <String>] [-ExportWitd]

As you can see, get-help thinks that WorkItemType is optional (the square brackets around the name and the type).

The actual answer came in the form of the parameter attribute:

[parameter(Mandatory = $true)]
[string] $WorkItemType

Now when I run the script without the WorkItemType parameter I get prompted to supply the required parameters as a read prompt, rather than nasty exceptions:

cmdlet UpdateTFSWorItems.ps1 at command pipeline position 1
Supply values for the following parameters:

However, this also has some fairly major consequences:

It converts your script into an "Advanced Function", as some of the documentation on TechNet for this states:

[T]o be recognized as an advanced function (rather than a simple function), a function must have either the CmdletBinding attribute or the Parameter attribute, or both.

There doesn't appear to be a way to apply one or other of these attributes and not be recognised as an advanced function.

Because your script is now "advanced", get-help is a bit different:

PS C:\Scripts> get-help .\UpdateTFSWorItems.ps1
UpdateTFSWorItems.ps1 [-WorkItemType] <String> [[-ProjectsToUse] <String>] [-ExportWitd]
[-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>]
[-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>]
[-OutBuffer <Int32>]

Where did all those extra parameters come from? Your function now supports all the "Common Parameters", this is more clearly stated if you add some help documentation to your script:

.Parameter WorkItemType
    Required. The name of the work item type you want to update in TFS.
.Parameter ProjectsToUse
    New or Legacy, defaults to New.

Calling get-help now results in the following syntax line being auto-generated:

    C:\Scripts\UpdateTFSWorItems.ps1 [-WorkItemType] <String> [[-ProjectsToUse] <String>]
    [-ExportWitd] [<CommonParameters>]

In general though I think this is a bonus, as it allows me to call the write-verbose and write-debug methods to get additional output and breakpoints.

If you're going to go to the effort of adding parameter documentation, you might as well also supply the HelpMessage parameter of the Parameter attribute:

[parameter(Mandatory = $true, HelpMessage = "The name of the work item type you want to update in TFS.")]
[string] $WorkItemType

Which then allows the user to get some help as they are prompted:

cmdlet UpdateTFSWorItems.ps1 at command pipeline position 1
Supply values for the following parameters:
(Type !? for Help.)
WorkItemType: !?
The name of the work item type you want to update in TFS

Gotcha with Write-Verbose

Write-host appears to take an array of objects and write a string representation of them out to the screen, which can be (ab)used in "interesting" ways:

write-host "Exporting WIT Definition from TFS Project" $selectedProjects[$i]

Results in output like:

Exporting WIT Definition from TFS Project Generic

Write-verbose (and indeed write-debug) explicitly only take a single string however, and calling them in the same way results in a nasty exception to that effect, so make sure you concatenate them:

write-verbose ("Project folder " + $selectedProjects[$i] + " already exists")

Which is slightly tedious.

Filed under: PowerShell, TFS