This management agent (MA) moves information about users from one Microsoft SharePoint Web site to another SharePoint Web site. It uses the IMAExtensibleFileImport interface to import information from an XML file. This MA includes a text file that contains the schema that is associated to this information, in Lightweight Directory Access Protocol (LDAP) Data Interchange Format (LDIF) format, which is written to the directory. The Schema Text File for the SharePoint Management Agent section contains a sample text file. This MA also contains the IMAExtensibleCallExport interface. This interface contains methods that are used to export the information that is obtained from the first SharePoint Web site to another SharePoint Web site.

You must create a Web Service that connects to both SharePoint Web sites that are sharing this information.

To create the MA

  1. In Microsoft Visual Studio, create a new Visual C# project named SharePointMA.

  2. Add a reference to the Microsoft.MetadirectoryServices namespace.

  3. Add the following code to the code pane for this class.

  4. Add a Web service to this project that connects to both SharePoint Web sites.

C#  Copy Code
using System;
using System.IO;
using System.Net;
using Microsoft.MetadirectoryServices;

namespace Microsoft.MetadirectoryServices.ManagementAgents.
SharePoint
{

 public class ManagementAgent : IMAExtensibleCallExport, 
								IMAExtensibleFileImport
 {

 UserGroupWebService ugws = null;
 WebsWebService wws = null;
 NetworkCredential creds = null;

 public ManagementAgent()
 {
 }

 //  / <summary>
 //  / <tla rid="fim_sync_short"/> call based export
 //  / </summary>
 public void GenerateImportFile( string filename, string 
 connectTo, string username, string password, 
 ConfigParameterCollection config,
 bool fullImport, TypeDescriptionCollection descriptions, 
 ref string customData )
 {

 SharePointUserCollection users = null;
 SharePointWebSiteCollection websites = null;
 //  NetworkCredential creds = null;
 string userGroupUrl = connectTo + "/_vti_bin/UserGroup.asmx";
 string websUrl = connectTo + "/_vti_bin/Webs.asmx";
 string[] sections = null;
 char[] splitChars = { '\\' };

 //  Delta imports are not supported.
 if( ! fullImport )
 throw new NotSupportedException( "Delta imports are not supported 
 by this management agent" );

 //  Remove import file if it already exists.
 if( File.Exists( filename ) )
 File.Delete( filename );
 //  Break out username from domain if specified in 
 // domain\username format.
 sections = username.Split( splitChars );

 //  Bind to URL.
 ugws = new UserGroupWebService( userGroupUrl );
 wws = new WebsWebService( websUrl );

 //  Figure out if the username and password was specified 
 //  in the domain\username
 //  format or not and generate credentials accordingly.
 if( sections.Length == 2 )
 creds = new NetworkCredential( sections[1], password, sections[0] );
 else
 creds = new NetworkCredential( username, password );

 //  Set credentials.
 ugws.Credentials = creds;
 wws.Credentials = creds;

 //  Get all users from SharePoint.
 users = new SharePointUserCollection( ugws.GetUserCollectionFromSite() );

 //  Get all Web site URLs from SharePoint.
 websites = new SharePointWebSiteCollection( wws.GetAllSubWebCollection() );

 //  Export Web sites.
 websites.Save( filename, false );

 //  Enumerate each Web site and retrieve roles associated to them.
 foreach( SharePointWebSite website in websites )
 {

 //  Connect to Web service for Web site.
 UserGroupWebService uswsWebSite = new UserGroupWebService( website.Url + 
  "/_vti_bin/UserGroup.asmx" );
 uswsWebSite.Credentials = creds;

 //  Enumerate through each Web site role.
 SharePointRoleCollection webSiteRoles = new SharePointRoleCollection( 
  website.Url, uswsWebSite.GetRoleCollectionFromWeb() );
 foreach( SharePointRole webSiteRole in webSiteRoles )
 {

 //  Enumerate through each user in role.
 SharePointUserCollection webSiteUsers = new SharePointUserCollection( 
  uswsWebSite.GetUserCollectionFromRole( webSiteRole.Name ) );
 foreach( SharePointUser webSiteUser in webSiteUsers )
 {
 users.AddRoleToUser( webSiteUser, webSiteRole );
 }

 }

 //  Export roles.
 webSiteRoles.Save( filename, false );

 }

 //  Export users.
 users.Save( filename, false );

 }

 //  / <summary>
 //  / <tla rid="fim_sync_short"/> call based export initialization.
 //  / </summary>
 public void BeginExport(
 string connectTo, string username, string password,
 ConfigParameterCollection config,
 TypeDescriptionCollection descriptions )
 {
 //  NetworkCredential creds = null;
 string userGroupUrl = connectTo + "/_vti_bin/UserGroup.asmx";
 string websUrl = connectTo + "/_vti_bin/Webs.asmx";
 string[] sections = null;
 char[] splitChars = { '\\' };

 //  Break out username from domain if specified in domain\username format.
 sections = username.Split( splitChars );

 //  Bind to URL.
 ugws = new UserGroupWebService( userGroupUrl );
 wws = new WebsWebService( websUrl );

 //  Figure out if the username and password was specified in the domain\username.
 //  Format or not and generate credentials accordingly.
 if( sections.Length == 2 )
 creds = new NetworkCredential( sections[1], password, sections[0] );
 else
 creds = new NetworkCredential( username, password );

 //  Set credentials.
 ugws.Credentials = creds;
 wws.Credentials = creds;

 }

 //  / <summary>
 //  / <tla rid="fim_sync_short"/> call based export
 //  / </summary>
 public void ExportEntry(
 ModificationType modificationType, string[] changedAttributes, CSEntry csentry )
 {

   switch( csentry.ObjectClass.ToString().ToLower() )
 {

 case "user":
 ExportUser( modificationType, csentry );
 break;

 case "userrole":
 ExportUserRole( modificationType, csentry );
 break;

 //  case "role":
 //  ExportRole( modificationType, csentry );
 //  break;

 //  case "website":
 //  ExportWebSite( modificationType, csentry );
 //  break;

 default:
 throw new NotSupportedException( "The object-class '" + csentry.
   ObjectClass + "' is not supported as an exportable object" );
 //  break;

 }


 }

 //  / <summary>
 //  / <tla rid="fim_sync_short"/> call based export complete
 //  / </summary>
 public void EndExport()
 {
 }

 private void ExportUser( ModificationType modificationType, CSEntry csentry )
 {

 //  User updates are done at a site level so the existing
 //  Web service connections are sufficient.

 switch( modificationType )
 {

 case ModificationType.Add:
 throw new NotImplementedException( "User adds are not allowed in SharePoint" );
 //  break;

 case ModificationType.Delete:
 ugws.RemoveUserFromSite( csentry[ "loginName" ].StringValue );
 break;

 case ModificationType.Replace:
 if( bool.Parse( csentry[ "isDomainGroup" ].StringValue ) )
 { //  group
 throw new NotImplementedException( "Group updates have not been implemented" );
 }
 else
 { //  user

 if( ! csentry[ "loginName" ].IsPresent )
 throw new AttributeNotPresentException( "loginName" );

 if( ! csentry[ "displayName" ].IsPresent )
 throw new AttributeNotPresentException( "displayName" );

 //  if( ! csentry[ "email" ].IsPresent )
 //  throw new AttributeNotPresentException( "email" );

 ugws.UpdateUserInfo( csentry[ "loginName" ].StringValue, 
 csentry[ "displayName" ].StringValue, csentry[ "email" ].
 StringValue, csentry[ "notes" ].StringValue );
 }
 break;

 }

 }

 private void ExportUserRole( ModificationType modificationType, CSEntry csentry )
 {

 string userGroupUrl = null;
 //  Role updates are done at a Web site level so we need to open new
 //  connections to the Web site we are modifying.

 if( ! csentry[ "url" ].IsPresent )
 throw new AttributeNotPresentException( "url" );
 userGroupUrl = csentry[ "url" ].StringValue + "/_vti_bin/UserGroup.asmx";
 ugws = new UserGroupWebService( userGroupUrl );
 ugws.Credentials = creds;

 switch( modificationType )
 {

 case ModificationType.Add:

 if( ! csentry[ "name" ].IsPresent )
 throw new AttributeNotPresentException( "name" );

 if( ! csentry[ "displayName" ].IsPresent )
 throw new AttributeNotPresentException( "displayName" );

 if( ! csentry[ "loginName" ].IsPresent )
 throw new AttributeNotPresentException( "loginName" );

 //  if( ! csentry[ "email" ].IsPresent )
 //  throw new AttributeNotPresentException( "email" );

 ugws.AddUserToRole( csentry[ "name" ].StringValue, csentry[ "displayName" ].StringValue,
 csentry[ "loginName" ].StringValue,
 csentry[ "email" ].StringValue, csentry[ "notes" ].StringValue );

 break;

 case ModificationType.Delete:

 if( ! csentry[ "name" ].IsPresent )
 throw new AttributeNotPresentException( "name" );

 if( ! csentry[ "loginName" ].IsPresent )
 throw new AttributeNotPresentException( "loginName" );

 ugws.RemoveUserFromRole( csentry[ "name" ].StringValue, csentry[ "loginName" ].StringValue );

 break;

 case ModificationType.Replace:
 throw new NotImplementedException( "User role updates are not allowed in SharePoint" );
 //  break;

 }

 }

//  private void ExportRole( ModificationType modificationType, CSEntry csentry )
//  {
//  //  switch( modificationType )
//  {
//  //  case ModificationType.Add:
//  break;
//  //  case ModificationType.Delete:
//  break;
//  //  case ModificationType.Replace:
//  break;
//  //  }
//  //  }

//  private void ExportWebSite( ModificationType modificationType, CSEntry csentry )
//  {
//  //  switch( modificationType )
//  {
//  //  case ModificationType.Add:
//  break;
//  //  case ModificationType.Delete:
//  break;
//  //  case ModificationType.Replace:
//  break;
//  //  }
//  //  }

 }
}

Adding a SharePoint Role

The next piece that you add to this project performs miscellaneous tasks, such as creating helper functions and import and export files.

To create the class

  1. In Solution Explorer, right-click the project name, point to Add, and then click Add Class.

  2. Select the Class icon.

  3. In the Name field, type SharepointRole.cs.

  4. Click Open.

  5. Add the following code for this class.

C#  Copy Code
using System;
using System.Collections;
using System.Xml;
using System.IO;

namespace Microsoft.MetadirectoryServices.ManagementAgents.SharePoint
{

  public class SharePointRoleCollection : IEnumerator, IEnumerable
  {

  protected ArrayList roles  = new ArrayList();
  protected int  position  = -1;

  public SharePointRoleCollection()
  {
  }

  public SharePointRoleCollection( string Url, XmlNode XmlRoleCollection )
  {

  for( int i=0; i<XmlRoleCollection.ChildNodes.Item( 0 ).ChildNodes.Count; i++ )
  {
  XmlNode xmlRole = XmlRoleCollection.ChildNodes.Item( 0 ).ChildNodes.Item( i );

  SharePointRole role = new SharePointRole(  xmlRole.Attributes[ "ID" ].Value,
  xmlRole.Attributes[ "Name" ].Value,
  xmlRole.Attributes[ "Description" ].Value,
  Url );

  this.roles.Add( role );
  }

  }

  /// <summary>
  /// Add a SharePoint role to the collection
  /// </summary>
  /// <param name="WebSite"></param>
  public void Add( SharePointRole Role )
  {
  this.roles.Add( Role );
  }

  /// <summary>
  /// Remove SharePoint role from the collection
  /// </summary>
  /// <param name="WebSite"></param>
//  public void Remove( SharePointRole Role )
//  {
//  // ArrayList.Remove() calls Object.Equals() for equality match
//  roles.Remove( Role );
//  }

  /// <summary>
  /// Returns the number of SharePoint roles within the collection
  /// </summary>
//  public int Count
//  {
//  get
//  {
//  return roles.Count;
//  }
//  }

  public IEnumerator GetEnumerator()
  {
  return (IEnumerator)this;
  }

  public void Reset()
  {
  this.position = -1;
  }

  public object Current
  {
  get
  {
  return this.roles[ this.position ];
  }
  }

  public bool MoveNext()
  {
  if( this.position < roles.Count - 1 )
  {
  ++this.position;
  return true;
  }

  return false;
  }

  /// <summary>
  /// Saves role collection as an <tla rid="fim_sync_short"/> AVP file
  /// </summary>
  /// <param name="Filename"></param>
  /// <param name="Overwrite"></param>
  public void Save( string Filename, bool Overwrite )
  {

  if( File.Exists( Filename ) )
  {
  if( Overwrite )
  File.Delete( Filename );
//  else
//  throw new IOException( "The file '" + Filename + "' already exists" );
  }

  StreamWriter importFile = new StreamWriter( Filename, true, System.Text.Encoding.Default );

  // Enumerate all roles.
  foreach( SharePointRole role in this.roles )
  {
  // Anchor for roles will be the URL+ID.

  importFile.WriteLine( "objectClass: role" );
  importFile.WriteLine( "anchor: " + role.Url + "_" + role.Id );
  importFile.WriteLine( "url: {0}", role.Url );
  importFile.WriteLine( "id: {0}", role.Id );
  importFile.WriteLine( "name: {0}", role.Name );
  importFile.WriteLine( "description: {0}", role.Description );
  importFile.WriteLine();

  // Force flush to disk in case we crash for debugging purposes.
  importFile.Flush();

  }

  importFile.Close();

  }

  }

  public class SharePointRole
  {

  protected string id  = null;
  protected string name  = null;
  protected string description  = null;
  protected string url  = null;

  public SharePointRole( string Id, string Name, string Description, string Url )
  {

  id  = Id;
  name  = Name;
  description  = Description;
  url  = Url;

  }

  /// <summary>
  /// Role ID
  /// </summary>
  public string Id
  {
  get
  {
  return this.id;
  }
  }

  /// <summary>
  /// Role name
  /// </summary>
  public string Name
  {
  get
  {
  return this.name;
  }
  }

  /// <summary>
  /// Role description
  /// </summary>
  public string Description
  {
  get
  {
  return this.description;
  }
  }

  /// <summary>
  /// Web site that role belongs to
  /// </summary>
  public string Url
  {
  get
  {
  return this.url;
  }
  }

  public bool Equals( SharePointRole Role )
  {
  if( Role.Id == this.id )
  return true;

  return false;
  }

  }
}

Adding a SharePoint User

The next piece that you add to this project performs miscellaneous tasks, such as creating helper functions and import and export files.

To create the class

  1. In Solution Explorer, right-click the project name, point to Add, and then click Add Class.

  2. Select the Class icon.

  3. In the Name field, type SharepointUser.cs.

  4. Click Open.

  5. Add the following code to the code pane for this class.

C#  Copy Code
using System;
using System.Collections;
using System.Xml;
using System.IO;

namespace Microsoft.MetadirectoryServices.ManagementAgents.SharePoint
{

  public class SharePointUserCollection : IEnumerator, IEnumerable
  {

  protected ArrayList users  = new ArrayList();
  protected int  position  = -1;

  public SharePointUserCollection()
  {
  }

  public SharePointUserCollection( XmlNode XmlUserCollection )
  {

  for( int i=0; i<XmlUserCollection.ChildNodes.Item( 0 ).ChildNodes.Count; i++ )
  {
  XmlNode xmlUser = XmlUserCollection.ChildNodes.Item( 0 ).ChildNodes.Item( i );

  SharePointUser user = new SharePointUser(  xmlUser.Attributes[ "ID" ].Value,
  xmlUser.Attributes[ "Email" ].Value,
  xmlUser.Attributes[ "Name" ].Value,
  bool.Parse( xmlUser.Attributes[ "IsDomainGroup" ].Value ),
  bool.Parse( xmlUser.Attributes[ "IsSiteAdmin" ].Value ),
  xmlUser.Attributes[ "LoginName" ].Value,
  xmlUser.Attributes[ "Notes" ].Value,
  xmlUser.Attributes[ "Sid" ].Value );

  // Add user to collection.
  this.users.Add( user );
  }

  }

  /// <summary>
  /// Add a SharePoint user to the collection
  /// </summary>
  /// <param name="User"></param>
  public void AddSharePointUser( SharePointUser User )
  {
  this.users.Add( User );
  }

  /// <summary>
  /// Remove SharePoint user from the collection
  /// </summary>
  /// <param name="User"></param>
//  public void RemoveSharePointUser( SharePointUser User )
//  {
//  // ArrayList.Remove() calls Object.Equals() for equality match
//  users.Remove( User );
//  }

  /// <summary>
  /// Adds a role to an existing SharePoint user in the collection
  /// </summary>
  /// <param name="User"></param>
  /// <param name="Role"></param>
  public void AddRoleToUser( SharePointUser User, SharePointRole Role )
  {
  int pos = GetUserIndex( User );

  // Check if a position was returned.
  if( pos == -1 )
  throw new ArgumentOutOfRangeException( "The user '" + User.LoginName + "' was not found" );

  ((SharePointUser) this.users[ pos ]).AddRole( Role );

  }

  /// <summary>
  /// Gets the position number in collection of a given user.  Zero based index.
  /// </summary>
  /// <param name="User"></param>
  private int GetUserIndex( SharePointUser User )
  {

  for( int i=0; i<this.users.Count; i++ )
  if( ((SharePointUser)this.users[ i ]).Equals( User ) )
  return i;

  return -1;

  }

  /// <summary>
  /// Returns the number of SharePoint users within the collection
  /// </summary>
//  public int Count
//  {
//  get
//  {
//  return users.Count;
//  }
//  }

  public IEnumerator GetEnumerator()
  {
  return (IEnumerator)this;
  }

  public void Reset()
  {
  this.position = -1;
  }

  public object Current
  {
  get
  {
  return this.users[ position ];
  }
  }

  public bool MoveNext()
  {
  if( this.position < users.Count - 1 )
  {
  ++this.position;
  return true;
  }

  return false;
  }

  /// <summary>
  /// Saves user collection as an <tla rid="fim_sync_short"/> AVP file
  /// </summary>
  /// <param name="Filename"></param>
  /// <param name="Overwrite"></param>
  public void Save( string Filename, bool Overwrite )
  {

  if( File.Exists( Filename ) )
  {
  if( Overwrite )
  File.Delete( Filename );
//  else
//  throw new IOException( "The file '" + Filename + "' already exists" );
  }

  StreamWriter importFile = new StreamWriter( Filename, true, System.Text.Encoding.Default );

  // Enumerate all users.
  foreach( SharePointUser user in this.users )
  {
  // Anchor for users can be either the ID or the LOGINNAME.

  importFile.WriteLine( "objectClass: user" );
  importFile.WriteLine( "anchor: " + user.Id );
  importFile.WriteLine( "id: {0}", user.Id );
  importFile.WriteLine( "email: {0}", user.Email );
  importFile.WriteLine( "displayName: {0}", user.Name );
  importFile.WriteLine( "isDomainGroup: {0}", user.IsDomainGroup.ToString() );
  importFile.WriteLine( "isSiteAdmin: {0}", user.IsSiteAdmin.ToString() );
  importFile.WriteLine( "loginName: {0}", user.LoginName );
  importFile.WriteLine( "notes: {0}", user.Notes );
  importFile.WriteLine( "objectSid: {0}", user.ObjectSid );
  importFile.WriteLine();

  // Force flush to disk in case we crash for debugging purposes.
  importFile.Flush();

  // Enumerate all roles.
  foreach( SharePointRole role in user.Roles )
  {

  // Anchor for roles is the ROLEID+LOGINNAME+URL.

  importFile.WriteLine( "objectClass: userRole" );
  importFile.WriteLine( "anchor: " + role.Url + "_" + role.Id + "_" + user.LoginName );
  importFile.WriteLine( "loginName: {0}", user.LoginName );
  importFile.WriteLine( "objectSid: {0}", user.ObjectSid );
//  importFile.WriteLine( "email: {0}", user.Email );
//  importFile.WriteLine( "displayName: {0}", user.Name );
//  importFile.WriteLine( "notes: {0}", user.Notes );
  importFile.WriteLine( "id: {0}", role.Id );
  importFile.WriteLine( "name: {0}", role.Name );
  importFile.WriteLine( "url: {0}", role.Url );
  importFile.WriteLine();

  // Force flush to disk in case we crash for debugging purposes.
  importFile.Flush();

  }

  }

  importFile.Close();

  }

  }

  public class SharePointUser
  {

  protected string  id  = null;
  protected string  email  = null;
  protected string  name  = null;
  protected bool  isDomainGroup  = false;
  protected bool  isSiteAdmin  = false;
  protected string  loginName  = null;
  protected string  notes  = null;
  protected string  objectSid  = null;
  protected SharePointRoleCollection  roles  = new SharePointRoleCollection();

  public SharePointUser( 
  string Id, 
  string Email, 
  string Name, 
  bool IsDomainGroup, 
  bool IsSiteAdmin, 
  string LoginName, 
  string Notes, 
  string ObjectSid )
  {

  this.id  = Id;
  this.email  = Email;
  this.name  = Name;
  this.isDomainGroup  = IsDomainGroup;
  this.isSiteAdmin  = IsSiteAdmin;
  this.loginName  = LoginName;
  this.notes  = Notes;
  this.objectSid  = ObjectSid;

  }

  public string Id
  {
  get
  {
  return this.id;
  }
  }

  public string Email
  {
  get
  {
  return this.email;
  }
  }

  public string Name
  {
  get
  {
  return this.name;
  }
  }

  public bool IsDomainGroup
  {
  get
  {
  return this.isDomainGroup;
  }
  }

  public bool IsSiteAdmin
  {
  get
  {
  return this.isSiteAdmin;
  }
  }

  public string LoginName
  {
  get
  {
  return this.loginName;
  }
  }

  public string Notes
  {
  get
  {
  return this.notes;
  }
  }

  public string ObjectSid
  {
  get
  {
  return this.objectSid;
  }
  }

  public SharePointRoleCollection Roles
  {
  get
  {
  return this.roles;
  }
  }

  public void AddRole( SharePointRole Role )
  {
  this.roles.Add( Role );
  }

//  public void RemoveRole( SharePointRole Role )
//  {
//  roles.Remove( Role );
//  }

//  public static bool operator == ( SharePointUser User1, SharePointUser User2 )
//  {
//  return User1.Equals( User2 );
//  }

//  public static bool operator != ( SharePointUser User1, SharePointUser User2 )
//  {
//  return ! User1.Equals( User2 );
//  }

  public bool Equals( SharePointUser User )
  {
  // loginName is unique for SharePoint. This string value is generated 
  // by SharePoint when the user is referenced for the first time. Subsequently
  // if the user's samAccountName changes, this value will not change in SharePoint.
  if( User.loginName.ToLower() == this.loginName.ToLower() )
  return true;

  return false;
  }

  }
}

Adding a SharePoint Web Site

The next piece that you add to this project performs miscellaneous tasks, such as creating helper functions and import and export files.

To create the class

  1. In Solution Explorer, right-click the project name, point to Add, and then click Add Class.

  2. Select the Class icon.

  3. In the Name field, type SharePointWebSite.cs.

  4. Click Open.

  5. Add the following code to the code pane for this class.

C#  Copy Code
using System;
using System.Collections;
using System.Xml;
using System.IO;

namespace Microsoft.MetadirectoryServices.ManagementAgents.SharePoint
{

  public class SharePointWebSiteCollection : IEnumerator, IEnumerable
  {

  protected ArrayList websites = new ArrayList();
  protected int  position = -1;

  public SharePointWebSiteCollection()
  {
  }

  public SharePointWebSiteCollection( XmlNode XmlWebSiteCollection )
  {

  for( int i=0; i<XmlWebSiteCollection.ChildNodes.Count; i++ )
  {

  XmlNode xmlWebSite = XmlWebSiteCollection.ChildNodes[ i ];

  SharePointWebSite website = new SharePointWebSite(  xmlWebSite.Attributes[ "Title" ].Value,
  xmlWebSite.Attributes[ "Url" ].Value );

  this.websites.Add( website );

  }

  }

  /// <summary>
  /// Add a SharePoint Web site to the collection
  /// </summary>
  /// <param name="WebSite"></param>
  public void Add( SharePointWebSite WebSite )
  {
  this.websites.Add( WebSite );
  }

  /// <summary>
  /// Remove SharePoint Web site from the collection
  /// </summary>
  /// <param name="WebSite"></param>
//  public void Remove( SharePointWebSite WebSite )
//  {
//  // ArrayList.Remove() calls Object.Equals() for equality match
//  websites.Remove( WebSite );
//  }

  /// <summary>
  /// Returns the number of SharePoint Web sites within the collection
  /// </summary>
  public int Count
  {
  get
  {
  return this.websites.Count;
  }
  }

  public IEnumerator GetEnumerator()
  {
  return (IEnumerator)this;
  }

  public void Reset()
  {
  this.position = -1;
  }

  public object Current
  {
  get
  {
  return this.websites[ this.position ];
  }
  }

  public bool MoveNext()
  {
  if( position < this.websites.Count - 1 )
  {
  ++this.position;
  return true;
  }

  return false;
  }

  /// <summary>
  /// Saves website collection as an <tla rid="fim_sync_short"/> AVP file
  /// </summary>
  /// <param name="Filename"></param>
  /// <param name="Overwrite"></param>
  public void Save( string Filename, bool Overwrite )
  {

  if( File.Exists( Filename ) )
  {
  if( Overwrite )
  File.Delete( Filename );
//  else
//  throw new IOException( "The file '" + Filename + "' already exists" );
  }

  StreamWriter importFile = new StreamWriter( Filename, true, System.Text.Encoding.Default );

  // Enumerate all Web sites.
  foreach( SharePointWebSite website in this.websites )
  {
  // Anchor for Web sites will be the URL.

  importFile.WriteLine( "objectClass: website" );
  importFile.WriteLine( "anchor: " + website.Url );
  importFile.WriteLine( "url: {0}", website.Url );
  importFile.WriteLine( "title: {0}", website.Title );
  importFile.WriteLine();

  // Force flush to disk in case we crash for debugging purposes.
  importFile.Flush();

  }

  importFile.Close();

  }

  }

  public class SharePointWebSite
  {

  protected string title  = null;
  protected string url  = null;

  public SharePointWebSite( string Title, string Url )
  {
  this.title = Title;
  this.url = Url;

  // Remove slash from end of URL before storing.
  this.url.TrimEnd( new char[] { '/' } );
  }

  /// <summary>
  /// Title of SharePoint Web site
  /// </summary>
  public string Title
  {
  get
  {
  return this.title;
  }
  }

  /// <summary>
  /// URL to SharePoint Web site
  /// </summary>
  public string Url
  {
  get
  {
  return this.url;
  }
  }

  public bool Equals( SharePointWebSite WebSite )
  {
  if( WebSite.Title.ToLower() == this.title.ToLower() )
  return true;

  return false;
  }

  }

}

Adding the Web Services

Next, you add the Web services to the project. You must add the following Web services:

  • UserGroupWebService

  • WebsWebService

XML Files

Next, you add several XML files to this project:

GetAllSubWebCollection

  1. In Solution Explorer, right-click the project name, point to Add, and then click Add New Item.

  2. Select the XML File icon.

  3. In the Name field, type GetAllSubWebCollection.xml.

  4. Click Open.

  5. Add the following code to the code pane for this class.

Xml  Copy Code
<?xml version="1.0" encoding="utf-8" ?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
  <GetAllSubWebCollectionResponse xmlns="
 http://schemas.microsoft.com/sharepoint/soap/">
  <GetAllSubWebCollectionResult>
  <Webs>
  <Web Title="Team Web Site" Url="http://contosotestwss/sites" />
  <Web Title="sub site level 1" Url="http://contosotestwss/sites/level1" />
  <Web Title="sub site level 2" 
  Url="http://contosotestwss/sites/level1/level2" />
  </Webs>
  </GetAllSubWebCollectionResult>
  </GetAllSubWebCollectionResponse>
  </soap:Body>
</soap:Envelope>

GetGroupCollectionFromWeb

  1. In Solution Explorer, right-click the project name, point to Add, and then click Add New Item.

  2. Select the XML File icon.

  3. In the Name field, type GetGroupCollectionFromWeb.xml.

  4. Click Open.

  5. Add the following code to the code pane for this class.

Xml  Copy Code
<?xml version="1.0" encoding="utf-8" ?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
  <GetGroupCollectionFromWebResponse xmlns="
  http://schemas.microsoft.com/sharepoint/soap/directory/">
  <GetGroupCollectionFromWebResult>
  <GetGroupCollectionFromWeb>
  <Groups></Groups>
  </GetGroupCollectionFromWeb>
  </GetGroupCollectionFromWebResult>
  </GetGroupCollectionFromWebResponse>
  </soap:Body>
</soap:Envelope>

GetRoleCollectionFromUser

  1. In Solution Explorer, right-click the project name, point to Add, and then click Add New Item.

  2. Select the XML File icon.

  3. In the Name field, type GetRoleCollectionFromUser.xml.

  4. Click Open.

  5. Add the following code to the code pane for this class.

Xml  Copy Code
<?xml version="1.0" encoding="utf-8" ?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
  <GetRoleCollectionFromUserResponse xmlns="
  http://schemas.microsoft.com/sharepoint/soap/directory/">
  <GetRoleCollectionFromUserResult>
  <GetRoleCollectionFromUser>
  <Roles>
  <Role ID="1073741828" Name="Web Designer" Description="Can 
  create lists and document libraries and customize pages in the Web site."
  Type="4" />
  </Roles>
  </GetRoleCollectionFromUser>
  </GetRoleCollectionFromUserResult>
  </GetRoleCollectionFromUserResponse>
  </soap:Body>
</soap:Envelope>

GetRoleCollectionFromWeb

  1. In Solution Explorer, right-click the project name, point to Add, and then click Add New Item.

  2. Select the XML File icon.

  3. In the Name field, type GetRoleCollectionFromWeb.xml.

  4. Click Open.

  5. Add the following code to the code pane for this class.

Xml  Copy Code
<?xml version="1.0" encoding="utf-8" ?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
  <GetRoleCollectionFromWebResponse xmlns="
  http://schemas.microsoft.com/sharepoint/soap/directory/">
  <GetRoleCollectionFromWebResult>
  <GetRoleCollectionFromWeb>
  <Roles>
  <Role ID="1073741825" Name="Guest" Description="Can view 
 specific lists or document libraries when given permissions."
  Type="1" />
  <Role ID="1073741826" Name="Reader" Description="Has 
 read-only access to the Web site."
  Type="2" />
  <Role ID="1073741827" Name="Contributor" Description="Can 
 add content to existing document libraries and lists."
  Type="3" />
  <Role ID="1073741828" Name="Web Designer" Description="Can 
 create lists and document libraries and customize pages in the Web site."
  Type="4" />
  <Role ID="1073741829" Name="Administrator" Description="Has 
 full control of the Web site."
  Type="5" />
  </Roles>
  </GetRoleCollectionFromWeb>
  </GetRoleCollectionFromWebResult>
  </GetRoleCollectionFromWebResponse>
  </soap:Body>
</soap:Envelope>

GetUserCollectionFromRole

  1. In Solution Explorer, right-click the project name, point to Add, and then click Add New Item.

  2. Select the XML File icon.

  3. In the Name field, type GetUserCollectionFromRole.xml.

  4. Click Open.

  5. Add the following code to the code pane for this class.

Xml  Copy Code
<?xml version="1.0" encoding="utf-8" ?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
  <GetUserCollectionFromRoleResponse xmlns="
  http://schemas.microsoft.com/sharepoint/soap/directory/">
  <GetUserCollectionFromRoleResult>
  <GetUserCollectionFromRole>
  <Users>
  <User ID="13" Sid="S-1-5-21-1754194003-3599853862-792115811-512" 
  Name="contosotestdom\domain admins"
  LoginName="CONTOSOTESTDOM\domain admins" Email="" Notes="" 
  IsSiteAdmin="False" IsDomainGroup="True" />
  <User ID="7" Sid="S-1-5-21-1754194003-3599853862-792115811-2081" 
  Name="Browne, Kevin F."
  LoginName="CONTOSOTESTDOM\kevin" Email="kevin@contoso.com" 
  Notes="" IsSiteAdmin="False"
  IsDomainGroup="False" />
  </Users>
  </GetUserCollectionFromRole>
  </GetUserCollectionFromRoleResult>
  </GetUserCollectionFromRoleResponse>
  </soap:Body>
</soap:Envelope>

GetUserCollectionFromSite

  1. In Solution Explorer, right-click the project name, point to Add, and then click Add New Item.

  2. Select the XML File icon.

  3. In the Name field, type GetUserCollectionFromSite.xml.

  4. Click Open.

  5. Add the following code to the code pane for this class.

Xml  Copy Code
<?xml version="1.0" encoding="utf-8" ?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
  <GetUserCollectionFromSiteResponse xmlns="
  http://schemas.microsoft.com/sharepoint/soap/directory/">
  <GetUserCollectionFromSiteResult>
  <GetUserCollectionFromSite>
  <Users>
  <User ID="3" Sid="S-1-5-21-4159163342-392914069-629406974-500" Name=
  ""LoginName="CONTOSOTESTWSS\Administrator"
  Email="" Notes="" IsSiteAdmin="False" IsDomainGroup="False" />
  <User ID="4" Sid="S-1-5-21-1754194003-3599853862-792115811-500" 
  Name="Administrator" LoginName="CONTOSOTESTDOM\Administrator"
  Email="" Notes="" IsSiteAdmin="False" IsDomainGroup="False" />
  <User ID="1" Sid="S-1-5-21-1754194003-3599853862-792115811-1118" 
  Name="gary yukish" LoginName="CONTOSOTESTDOM\gary"
  Email="gary@contosotestdom.nttest.contoso.com" Notes="" 
  IsSiteAdmin="True" IsDomainGroup="False" />
  <User ID="13" Sid="S-1-5-21-1754194003-3599853862-792115811-512" 
  Name="contosotestdom\domain admins"
  LoginName="CONTOSOTESTDOM\domain admins" Email="" Notes="" 
  IsSiteAdmin="False" IsDomainGroup="True" />
  <User ID="9" Sid="S-1-5-21-1754194003-3599853862-792115811-2472" 
  Name="Kretowicz, Marcin"
  LoginName="CONTOSOTESTDOM\marcin" Email="MARCIN@contoso.com" 
  Notes="" IsSiteAdmin="False"
  IsDomainGroup="False" />
  <User ID="7" Sid="S-1-5-21-1754194003-3599853862-792115811-2081" 
  Name="Browne, Kevin F."
  LoginName="CONTOSOTESTDOM\kevin" Email="KEVIN@contoso.com" Notes="
  " IsSiteAdmin="False"
  IsDomainGroup="False" />
  <User ID="12" Sid="S-1-5-21-1754194003-3599853862-792115811-2464"
   Name="Kostidou, Stella"
  LoginName="CONTOSOTESTDOM\stella" Email="STELLA@contoso.com" Notes="
  " IsSiteAdmin="False"
  IsDomainGroup="False" />
  <User ID="10" Sid="S-1-5-21-1754194003-3599853862-792115811-2471"
  Name="Mahawar, Hemant"
  LoginName="CONTOSOTESTDOM\hemant" Email="HEMANT@contoso.com"
  Notes="" IsSiteAdmin="False"
  IsDomainGroup="False" />
  <User ID="11" Sid="S-1-5-21-1754194003-3599853862-792115811-2460" 
  Name="Wang, Jian" LoginName="CONTOSOTESTDOM\jian"
  Email="jian@contoso.com" Notes="" IsSiteAdmin="False" 
  IsDomainGroup="False" />
  </Users>
  </GetUserCollectionFromSite>
  </GetUserCollectionFromSiteResult>
  </GetUserCollectionFromSiteResponse>
  </soap:Body>
</soap:Envelope>

Schema Text File for the SharePoint Management Agent

  1. In Solution Explorer, right-click the project name, point to Add, and then click Add New Item.

  2. Select the Text File icon.

  3. In the Name field, type SharePointMA.txt.

  4. Click Open.

  5. Add the following code to the code pane for this class.

  Copy Code
objectClass: user
anchor: anchor
id: id
email: email
displayName: displayName
isDomainGroup: isDomainGroup
isSiteAdmin: isSiteAdmin
loginName: loginName
notes: notes
objectSid: objectSid

objectClass: userRole
anchor: anchor
loginName: loginName
objectSid: objectSid
displayName: displayName
notes: notes
email: email
id: id
name: name
url: url

objectClass: role
anchor: anchor
url: url
id: id
name: name
description: description

objectClass: website
anchor: anchor
url: url
title: title

See Also