Silver Award WinnerSilver Award Winner

 


Applies To

  • FIM 2010 (R2)
  • MIM 2016

 


Summary

In a previous article, I gave you a script that can export all Metaverse user objects and their connections in a way that is easier for analysis. In this article, I will give you a fully supported tool that looks at the connector status at the management agent level.

Consider the following scenario: You've been asked to join a select group of objects/records in a data store to existing Metaverse objects. Upon synchronization you find a majority of objects joined to the Metaverse, but hundreds/thousands did not. How do you quickly and easily determine the subset of objects that did not join from the initial list provided? In other words, how can you determine the connector status of a bulk list of objects/records?

The Synchronization Manager UI allows you to search the connector space for a specific object by clicking on the Management Agents tool, then clicking on Search Connector Space:

In the Connector Space Search window, you can enter a DN of an object and determine Connector status:

 

This method works great if you need to look at a few connector space object details, but is not practical if you need to look at hundreds or thousands of connector space objects.

You can search the entire connector space, sort the Connector column, and then copy the rows that are showing as False (disconnectors):





This method works well assuming the number of connector space objects are reasonable and you're fine with doing some copying and pasting. When you have a connector space with hundreds of thousands or more, it takes a bit of time to load every single object in the interface, sort and then copy the data out to another file.

A second approach is using a slightly obscure command line tool that many customers have never used: CSEXPORT.EXE

CSEXPORT.EXE is a command-line tool included with Microsoft Identity Manager (and previous versions of the product) that allows exporting connector space details.

The file is located in \Program Files\Microsoft Forefront Identity Manager\2010\Synchronization Service\Bin and has the following usage:

Usage: CSEXPORT ma_name [filename] [/f[:]{d="DN"|r="rdn"|g="guid"|s|i|e|m|x}] [/o[:]{[e][b][h][d][p]}]
ma_name Name of MA to export
filename Filename (default is name of MA)
/f Filter objects to export (default is all objects, if this option is omitted):
 d Specify DN to export where DN is the distinguished name or anchor to export
 r Specify RDN to export where RDN is the relative distinguished name to export
 g Specify GUID to export where GUID is the globally unique identifier to export
 s Disconnectors
 i Import errors
 e Export errors
 m Pending imports
 x Pending exports
/o Output the following items (default is all items, if this option is omitted):
 e include error information
 b include only the hologram
 h include all tower holograms
 d include all tower deltas
 p include password set/change history

Example: csexport AD c:\temp\output.txt /f:d="CN=VRottmann,OU=TFCUsers,DC=TheFinancialCompany,DC=com"

The XML file c:\temp\output.txt is created that contains all sorts of information.

Here's what my output.txt file looks like:

Notice the <connector>0</connector> line. As you may suspect, a value of 0 indicates the object is a disconnector and a value of 1 indicates the object is a connector.

Thus, if we feed a file of DN's (C:\Temp\List.txt) to CSEXPORT.EXE and look at the connector value in /cs-objects/cs-object in each XML file, we would know if the object is a connector or a disconnector.

Listed below is a C# script that reads through an import file and exports the connector status, TRUE (meaning a connector) or FALSE (a disconnector).


Usage

GetConnectorStatusByFile.exe


C# Code

C:\Temp\List.txt is a text file of DNs to search with a DN on each row.

C:\TEMP\GetConnectorStatusByFile.tmp is a temporary file required by CSEXPORT.EXE 

001

002

003

004

005

006

007

008

009

010

011

012

013

014

015

016

017

018

019

020

021

022

023

024

025

026

027

028

029

030

031

032

033

034

035

036

037

038

039

040

041

042

043

044

045

046

047

048

049

050

051

052

053

054

055

056

057

058

059

060

061

062

063

064

065

066

067

068

069

070

071

072

073

074

075

076

077

078

079

080

081

082

083

084

085

086

087

088

089

090

using System;

using System.IO;

using System.Data;

using System.Data.SqlClient;

using System.Collections.Generic;

using System.Text;

using System.Xml;

using System.Diagnostics;

using System.DirectoryServices;

namespace GetConnectorStatusByFile

{

    class Program

    {

        const string TempFile = @"C:\TEMP\GetConnectorStatusByFile.tmp";

        static void LaunchCommandLineApp(string MA, string DN)

        {

            // For the example

            //          string MA = "AD";

            //          string DN = "CN=VRottmann,OU=TFCUsers,DC=TheFinancialCompany,DC=com";

            ProcessStartInfo startInfo = new ProcessStartInfo(@"C:\Program Files\Microsoft Forefront Identity Manager\2010\Synchronization Service\Bin\csexport.exe");

            startInfo.CreateNoWindow = false;

            startInfo.UseShellExecute = true;

            startInfo.FileName = @"C:\Program Files\Microsoft Forefront Identity Manager\2010\Synchronization Service\Bin\csexport.exe";

            startInfo.WindowStyle = ProcessWindowStyle.Hidden;

            startInfo.Arguments = '\u0022' + MA + '\u0022' + " " + TempFile + " " + "/f:d=" + '\u0022' + DN + '\u0022';

            startInfo.WorkingDirectory = @"C:\Program Files\Microsoft Forefront Identity Manager\2010\Synchronization Service\Bin\";

            using (Process exeProcess = Process.Start(startInfo))

            {

                exeProcess.WaitForExit();

            }

        }

        static void Main(string[] args)

        {

            string MA = string.Empty;

            MA = "AD";  // The name of the Management Agent you want to search

            string[] lines = System.IO.File.ReadAllLines(@"C:\Temp\List.txt");

            foreach (string DN in lines)

            {

                string connector = string.Empty;

                if (File.Exists(TempFile))

                {

                    File.Delete(TempFile);

                }

                LaunchCommandLineApp(MA, DN);

                XmlDocument xml = new XmlDocument();

                if (File.Exists(TempFile))

                {

                    xml.Load(TempFile);

                    XmlNodeList xnList = xml.SelectNodes("/cs-objects/cs-object");

                    foreach (XmlNode xn in xnList)

                    {

                        connector = xn["connector"].InnerText;

                        if (connector != null && connector.Length > 0)

                        {

                            string XMLOutput = connector.Substring(0, 1);

                            if (XMLOutput == "1")

                            {

                                Console.WriteLine(DN + ";" + "TRUE");

                            }

                            else

                            {

                                Console.WriteLine(DN + ";" + "FALSE");

                            }

                        }

                        else

                        {

                            Console.WriteLine(DN + ";" + "FALSE");

                        }

                    }

                    if (connector == string.Empty)

                    {

                        Console.WriteLine(DN + ";" + "FALSE");

                    }

                }

                else // file does not exist

                {

                    Console.WriteLine("FILE DOES NOT EXIST");

                }

                if (File.Exists(TempFile))

                {

                    File.Delete(TempFile);

                }

            }

        } // end else

    } }

note Note
To provide feedback about this article, create a post in the FIM TechNet Forum.

For more FIM related Windows PowerShell scripts, see the FIM ScriptBox