Partager via


Example: Call-Based Extension for SharePoint Groups

This management agent (MA) moves information about a group from one SharePoint Web site to another SharePoint Web site. It uses the IMAEXtensibleFileImport interface to import information from an XML file.

This MA is used in conjunction with a text file that contains the schema associated to this information, in LDIF format, which will be written to the directory. A sample text file is shown in the section Schema Text File.

This MA also contains the IMAExtensibleCallExport interface which contains methods used to export the information obtained from the first SharePoint Web site to another SharePoint Web site.

You need to create a Web Service that will connect to both SharePoint Web sites that are sharing information.

ms696070.wedge(en-us,VS.85).gifTo create this MA

  1. Create a new C# project named SharePointMA.

  2. Add a reference to Microsoft.MetadirectoryServices.

  3. Add the following code to the code pane for this class in a class called Class1.cs.

  4. Right click web reference in the solution explorer and select Add Web Reference.

  5. Type the following URL in the dialog box: http://<sharepoint-servername>/_vti_bin/usergroup.asmx. Set the local reference name to localhost.

  6. In the Class1.cs file that contains the copied source code, add the following using statement to the top of the class.

      using SharePointMA.localhost;
    
  7. Add a Web Service to this project that will connect to both SharePoint Web sites.

  8. Add the utilities, as described in Adding Utility Functions for this Management Agent.

    using System;
    using System.Xml;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Security.Principal;
    using System.Security.Permissions;
    using Microsoft.MetadirectoryServices;
    using System.Collections;
    using System.Collections.Specialized;
    
    namespace Microsoft.MetadirectoryServices.SharePoint
    {
      public class MAExtensibleSoap : IMAExtensibleCallExport, 
         IMAExtensibleFileImport
      {
        // WSS user group Web service.
        UserGroup ugs;
    
        string url        = null;
        string userName      = null;
        string userDomain    = null;
        string userPassword    = null;
    
        /// <summary>
        /// ILM 2007 FP1 call-based export.
        /// </summary>
        public void GenerateImportFile( string filename, 
                        string connectTo, 
                        string user, 
                        string password, 
                        ConfigParameterCollection config,
                        bool fullImport, 
                        TypeDescriptionCollection descriptions, 
                        ref string customData )
        {
    
          // Delta imports from SharePoint Web services are not
          // supported. If a delta import is specified,
          // let the administrator know.
          if( ! fullImport )
            throw new Exception( "Delta imports are not supported by this 
           management agent.  Change the configuration of this 
           management agent to a full import." );
    
    
          // If the file exists, delete it. If you do not do this,
          // the file will never get deleted because it will 
          // encounter an "object exists" error.
          if( File.Exists( filename ) )
            File.Delete( filename) ;
    
          string[] sections  = null;
          char[] splitChars  = { '\\' };
    
          // Break out the username from the domain if specified 
          // in domain\username format.
          sections = user.Split( splitChars );
    
          // Only the domain\username format is supported.
           if( sections.Length != 2 )
            throw new Exception( "Invalid username format 
             specified in management agent.  Specify username 
             in domain\\username format." );
    
          // Save some global information.
          userDomain    = sections[ 0 ];
          userName    = sections[ 1 ];
          userPassword  = password;
          url        = connectTo;
    
          // Bind to the Web service with credentials.
          SpMaUtils.BindToUserGroupWebService( url, userName, 
          userDomain, password, ref ugs );
    
          // Get the user collection by executing the Web method 
          // on a SharePoint server.
          ArrayList sharePointUsers = SpMaUtils.
           XmlUserCollectionToArrayList( ugs.GetUserCollectionFromSite() );
           SpMaUtils.WriteMiisImportFile( filename, sharePointUsers );
          
        }
    
        /// <summary>
        /// ILM 2007 FP1 call-based export initialization.
        /// </summary>
        public void BeginExport(  string connectTo, 
                      string user, 
                      string password,
                      ConfigParameterCollection config,
                      TypeDescriptionCollection descriptions )
        {
    
          string[] sections  = null;
          char[] splitChars  = { '\\' };
    
          // Break out the username from the domain if 
          // specified in the domain\username format.
          sections = user.Split( splitChars );
    
          // Only the domain\username format is supported.
          if( sections.Length != 2 )
            throw new Exception( "Invalid username format specified 
              in management agent.  Specify username in 
              domain\\username format." );
    
          // Save some global information.
          userName    = sections[ 1 ];
          userDomain    = sections[ 0 ];
          userPassword  = password;
          url        = connectTo;
    
          // Bind to the Web service with credentials.
          SpMaUtils.BindToUserGroupWebService( url, userName, 
          userDomain, password, ref ugs );
    
        }
    
        /// <summary>
        /// ILM 2007 FP1 call-based export.
        /// </summary>
        public void ExportEntry(  ModificationType 
                      modificationType, 
                      string[] changedAttributes, 
                      CSEntry csentry )
        {
    
          //
          // Validate that export attributes were found.
          //
    
          string displayName = SpMaUtils.GetCsEntryAttributeValue
             ( csentry, "displayName" );
          if( displayName.Length == 0 )
            throw new Exception( "No \"displayName\" 
            attribute was found" );
          
          string email = SpMaUtils.GetCsEntryAttributeValue
                  ( csentry, "email" );
          if( email.Length == 0 )
            throw new Exception( "No \"email\" 
             attribute was found" );
          
          string loginName = SpMaUtils.GetCsEntryAttributeValue
                   ( csentry, "loginName" );
          if( loginName.Length == 0 )
            throw new Exception( "No \"loginName\" 
                   attribute was found" );
          
          string notes = SpMaUtils.GetCsEntryAttributeValue
                  ( csentry, "notes" );
          // if( userNotes.Length == 0 )
          // throw new Exception( "No \"notes\" attribute was found" );
    
    
          switch( modificationType )
          {
    
            // new cs entry created
            case ModificationType.Add:
              throw new Exception("New identities cannot be 
              provisioned to SharePoint" );
    
            // exporting a delete
            case ModificationType.Delete:
              ugs.RemoveUserFromSite( loginName );
              break;
    
            // cs entry updated
            case ModificationType.Replace:
              ugs.UpdateUserInfo( loginName, displayName, email, 
                       notes );
              break;
    
          }
    
        }
    
        /// <summary>
        /// Call-based export complete.
        /// </summary>
        public void EndExport()
        {
        }
    
      }
    }

Adding Utility Functions for this Management Agent

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

ms696070.wedge(en-us,VS.85).gifTo create this class

  1. In the Solution Explorer pane, right-click the project name and navigate to Add > Add Class.
  2. Select the Class icon.
  3. In the Name field, write SpMaUtils.cs.
  4. Click Open.
  5. Add the following code to the code pane for this class.
    using System;
    using System.IO;
    using System.Net;
    using System.Xml;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Security.Principal;
    using System.Security.Permissions;
    using System.Collections;
    using System.Collections.Specialized;
    using System.Data;
    using System.Data.SqlClient;
    using Microsoft.Win32;
    using System.Web.Mail;
    
    namespace Microsoft.MetadirectoryServices.SharePoint
    {
    
     public class SpMaUtils
     {
    
     //  -------------------------------------------------------------
     //  Static variables
     //  -------------------------------------------------------------
    
     //  Import file information.
     internal static string strImportFileFormat = "iD: {0}\r\n" +
     "email: {1}\r\n" +
     "displayName: {2}\r\n" +
     "isDomainGroup: {3}\r\n" +
     "isSiteAdmin: {4}\r\n" +
     "loginName: {5}\r\n" +
     "notes: {6}\r\n" +
     "objectSid: {7}\r\n" +
     "\r\n";
    
     //  -------------------------------------------------------------
     //  Helper functions
     //  -------------------------------------------------------------
    
     //  / <summary>
     //  / Convert a SharePoint xml user node from the Web service to a 
     //  string array.
     //  / </summary>
     //  / <param name="xmlUserCollection">XML node of a user collection 
     //  returned by the SharePoint user collection Web method</param>
     //  / <returns>Name value collection for the user</returns>
     internal static NameValueCollection XmlUserToCollection
      (XmlNode xmlUser)
     {
     NameValueCollection user = new NameValueCollection();
    
     user.Add( "id", xmlUser.Attributes[ "ID" ].Value );
     user.Add( "email", xmlUser.Attributes[ "Email" ].Value );
     user.Add( "displayName", xmlUser.Attributes[ "Name" ].Value );
     user.Add( "isDomainGroup", xmlUser.Attributes
               [ "IsDomainGroup" ].Value );
     user.Add( "isSiteAdmin", xmlUser.Attributes
               [ "IsSiteAdmin" ].Value );
     user.Add( "loginName", xmlUser.Attributes[ "LoginName" ].Value );
     user.Add( "notes", xmlUser.Attributes[ "Notes" ].Value );
     user.Add( "objectSid", xmlUser.Attributes[ "Sid" ].Value );
    
     return user;
    
     }
    
     //  <summary>
     //  Convert a SharePoint xml user collection from the Web service  
     //  to an array of name value collections for each user.
     //  </summary>
     //  <param name="xmlUserCollection"></param>
     //  <returns>Array of name value collections for representing
     //  each user</returns>
     internal static ArrayList XmlUserCollectionToArrayList
      ( XmlNode xmlUserCollection )
     {
     ArrayList users = new ArrayList();
    
     for( int i=0; i<xmlUserCollection.ChildNodes.Item( 0 ).
      ChildNodes.Count; i++ )
     {
     //  Convert each user to a name value collection for properties.
     NameValueCollection user = XmlUserToCollection( xmlUserCollection.
      ChildNodes.Item( 0 ).ChildNodes.Item( i ) );
    
     //  Add the user property collection to the array.
     users.Add( user );
     }
    
     return users;
     }
    
     //  / <summary>
     //  / Gets a string attribute from the connected space and  
     //  / returns a blank string of the attrivute is not present
     //  / </summary>
     //  / <param name="csentry">Connected space entry object</param>
     //  / <param name="attribute">Attribute to retrieve</param>
     //  / <returns>Value of atrribute. Returns an empty string 
     //  / if attribute is not present</returns>
     internal static string GetCsEntryAttributeValue( CSEntry
       csentry, string attribute )
     {
     if( csentry[ attribute ].IsPresent )
     return csentry[ attribute ].StringValue;
     else
     return "";
     }
    
     //  / <summary>
     //  / Parses out the NETBIOS name of the domain based on a DN
     //  / </summary>
     //  / <param name="dn"></param>
     //  / <returns></returns>
     internal static string GetDomainNetBiosName( string dn )
     {
     //  -TODO-
     //  Need to call into win32 API. This currently assumes
     //  that the netbios name is the same as the fqdn, which
     //  may not be true.
    
     char[] splitChars = { ',' };
     string[] sections = dn.Split( splitChars );
    
     foreach( string section in sections )
     {
     //  If section begins with "DC=", then this indicatees the first  
     //  part of the string, which is the netbios name. Everything
     //  after the "=" character must be returned.
     if( section.Substring( 0, 3 ) == "DC=" )
     return section.Substring( 3 );
     }
    
     //  If the debugger stops here, no "DC=" section was found 
     //  in the DN passed in.
     return "";
    
     }
    
     //  / <summary>
     //  / Binds to the user group Web service.
     //  / </summary>
     //  / <param name="connectTo">Server name to bind to</param>
     //  / <param name="ssl">Boolean specifying whether or not SSL is 
     //  / required</param>
     //  / <param name="user">Username to bind as</param>
     //  / <param name="user">Domain to bind as</param>
     //  / <param name="password">Password to bind as</param>
     public static void BindToUserGroupWebService( string url, 
       string username, 
        string domain, string password, ref UserGroup ugs )
     {
     //  Connect to the Web service.
     ugs = new UserGroup( url );
    
     //  Authenticate based on credentials passed in
     ugs.Credentials = new NetworkCredential( username, password, 
      domain );
    
     }
    
     //  -------------------------------------------------------
     //  File manipulation
     //  -------------------------------------------------------
    
     //  / <summary>
     //  / Write a line to a file.
     //  / </summary>
     //  / <param name="filename">File to append to</param>
     //  / <param name="line">Line to write</param>
     internal static void WriteFile( string filename, string line )
     {
     StreamWriter sw = new StreamWriter( filename, true, System.Text.
       Encoding.Default );
     sw.WriteLine( line );
     sw.Close();
     }
    
     //  / <summary>
     //  / Writes ILM 2007 FP1 import file.
     //  / </summary>
     //  / <param name="filename">File to append to</param>
     //  / <param name="user">Name value collection of 
     //  / user properties</param>
     internal static void WriteMiisImportFile( string filename, 
      NameValueCollection user )
     {
    
     object[] args = { user[ "id" ], user[ "email" ], user[ "displayName" ], 
       user[ "isDomainGroup" ], user[ "isSiteAdmin" ], user[ "loginName" ], 
       user[ "notes" ], user[ "objectSid" ]
     };
    
     //  Write the file.
     WriteFile( filename, string.Format(SpMaUtils.strImportFileFormat, 
     args));
    
     }
    
     //  / <summary>
     //  / Creates an ILM 2007 FP1 import file
     //  / </summary>
     //  / <param name="filename"></param>
     //  / <param name="users"></param>
     internal static void WriteMiisImportFile(string filename, 
       ArrayList users)
     {
     //  Write each user.
     foreach( NameValueCollection user in users )
     WriteMiisImportFile( filename, user );
     }
    
     }
    
    }

Schema Text File for the SharePoint Management Agent

The schema that is used for this management agent is added using a text file. Create a text file and name it SharePointMA.txt and copy the following information to that file.

    iD: iD
    email: email
    displayName: displayName
    isDomainGroup: isDomainGroup
    isSiteAdmin: isSiteAdmin
    loginName: loginName
    notes: notes
    objectSid: objectSid

Send comments about this topic to Microsoft

Build date: 2/16/2009