第一个需求,登陆名称绑定计算机名( C#开发AD域控自动工具之四)

很快,我们迎来了第一个需求,OA新进员工流程中,需要域控:按员工号绑定工作站名称 。

 

功能设计如下:
1、    在AD域控服务器上部署自开发C# 中间件应用程序,调用微软提供的AD开发类库;实现对AD内元素(用户、OU等)的增删改查。


2、    对外使用WebService接口提供服务,调用该接口服务即可完成该操作。


3、AD域控中间件应用程序有详细的日志记录,对每一笔操作都记录到日志文件中。

 

泛微的OA通过WebService调用外部接口,这一块就交给小渔去搞定了。

一、我现在要在AD域控上摆一个WebService服务器出来,实现AD的操作。需要借助微软的WCF来开发:

在VS2017中建一个WCF服务

第一个需求,登陆名称绑定计算机名( C#开发AD域控自动工具之四)

我们还是把使用配置文件,这样可以方便部署到服务器上不同的IP去,

为什么一定要部署到AD服务器上,因为对用户密码的修改,需要在服务器上调用类库,

所以一开始虽然需求没涉及到用户密码,但我还是一劳永逸的把中间件程序部署在AD上。

第一个需求,登陆名称绑定计算机名( C#开发AD域控自动工具之四)

该服务全部的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using ActiveDs;
using System.DirectoryServices;
using System.Configuration;
using System.IO;

namespace WcfService1
{
    // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“Service1”。
    // 注意: 为了启动 WCF 测试客户端以测试此服务,请在解决方案资源管理器中选择 Service1.svc 或 Service1.svc.cs,然后开始调试。
    public class Service1 : IService1
    {

        //日志处理(1/4)
        public static StreamWriter sw = new StreamWriter("log.txt", true, Encoding.GetEncoding("gb2312"));

        public static string AD_admin = ConfigurationManager.AppSettings["AD_admin"];
        public static string AD_password = ConfigurationManager.AppSettings["AD_password"];
        public static string AD_LDAP = ConfigurationManager.AppSettings["AD_LDAP"];
        public static string AD_DC1 = ConfigurationManager.AppSettings["AD_DC1"];
        public static string AD_DC2 = ConfigurationManager.AppSettings["AD_DC2"];


        public string SetWorkstation(string AMAccountName,string hosts)
        {

            string temp;  
            try
            {
                //不指定OU,我们对根作查询操作
                DirectoryEntry objDE = new DirectoryEntry(AD_LDAP + "/" + "DC=" + AD_DC1 + ",DC=" + AD_DC2, AD_admin, AD_password);
                
                //用户找出来           
                DirectorySearcher objSearcher = new DirectorySearcher(objDE, "(&(sAMAccountName=" + AMAccountName + "))");
                SearchResult one = objSearcher.FindOne();

                if (one != null)
                {
                    DirectoryEntry de = one.GetDirectoryEntry();
                    string oldws = Convert.ToString(de.Properties["userWorkstations"].Value); //注意这里null用convert
                    de.Properties["userWorkstations"].Value = hosts;
                    de.CommitChanges();
                    temp = "success:true  message:oldws:"+ oldws+" newws:"+ hosts;
                }
                else
                {
                    temp = "success:false  message:没有这个登陆账号";
                }

            }
            catch (Exception ex)
            {               
                temp = "success:false  message:"+ ex.Message;
            }

            log(AMAccountName+","+ hosts+","+temp);
            return temp;
        }

        public void log(string s)
        {
            String line = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " " + s;          
            //日志处理(2/4)
            sw.WriteLine(line);
            //日志处理(3/4)
            sw.Flush(); //缓存区写文件
        }



    }
}

因为C#作了很多事情,所以代码很少,WCF项目不是产生执行文件,而是生成一个DLL文件。

二、我们还需要一个容器,我们建一个WINFORM项目

第一个需求,登陆名称绑定计算机名( C#开发AD域控自动工具之四)

项目中,我们引用启动刚才的DLL:

第一个需求,登陆名称绑定计算机名( C#开发AD域控自动工具之四)第一个需求,登陆名称绑定计算机名( C#开发AD域控自动工具之四)

 

WINFORM项目中的app.config配置,这里定义了端口8000:

<?xml version="1.0" encoding="utf-8"?>
<configuration>


  <runtime>
    <legacyUnhandledExceptionPolicy enabled="true"/>
  </runtime>

  <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
    </startup>

  <appSettings>   

    <add key="AD_admin" value="administrator"></add>
    <add key="AD_password" value="Test123456789"></add>
    <add key="AD_LDAP" value="LDAP://192.168.155.250"></add>
    <add key="AD_DC1" value="adserv"></add>
    <add key="AD_DC2" value="com"></add>

  </appSettings>

  <system.serviceModel>
    <services>
      <!--添加服务-->
      <service name="WcfService1.Service1" behaviorConfiguration="CalculatorServiceBehavior">
        <!--name 必须与代码中的host实例初始化的服务一样 behaviorConfiguration 行为配置 -->
        <host>
          <baseAddresses>
            <!--添加调用服务地址-->
            <add baseAddress="http://localhost:8000/"/>
          </baseAddresses>

        </host>
        <!--添加契约接口 contract="WcfDemo.IService1" WcfDemo.IService1为契约接口 binding="wsHttpBinding" wsHttpBinding为通过Http调用-->
        <endpoint address="" binding="basicHttpBinding" contract="WcfService1.IService1"></endpoint>
      </service>

    </services>
    <!--定义CalculatorServiceBehavior的行为-->
    <behaviors>
      <serviceBehaviors>
        <behavior name="CalculatorServiceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>

        </behavior>
      </serviceBehaviors>

    </behaviors>
  </system.serviceModel> 
  
</configuration>

三、在服务器上部署这个WINFORM+WCF服务就好,OA服务器可以通过调用这个webservice绑定用户中的登陆名和工作站名称。

 

注意对配置文件中变量的读取,并不是WCF项目里面的web.config, 而是在程序实例 WINFORM的app.config中。

 

 

------------2019-4-16-联合调试中发现一个问题----------------------

WS的配置文件中,要指定一下服务器的IP才好。

第一个需求,登陆名称绑定计算机名( C#开发AD域控自动工具之四)

 

----------2019-4-16下午加入了JSON消息返回---------------------------

 

第一个需求,登陆名称绑定计算机名( C#开发AD域控自动工具之四)

全部代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using ActiveDs;
using System.DirectoryServices;
using System.Configuration;
using System.IO;
using Newtonsoft;
using Newtonsoft.Json;

namespace WcfService1
{
    // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“Service1”。
    // 注意: 为了启动 WCF 测试客户端以测试此服务,请在解决方案资源管理器中选择 Service1.svc 或 Service1.svc.cs,然后开始调试。
    public class Service1 : IService1    {

        //日志处理(1/4)
        public static StreamWriter sw = new StreamWriter("log.txt", true, Encoding.GetEncoding("gb2312"));

        public static string AD_admin = ConfigurationManager.AppSettings["AD_admin"];
        public static string AD_password = ConfigurationManager.AppSettings["AD_password"];
        public static string AD_LDAP = ConfigurationManager.AppSettings["AD_LDAP"];
        public static string AD_DC1 = ConfigurationManager.AppSettings["AD_DC1"];
        public static string AD_DC2 = ConfigurationManager.AppSettings["AD_DC2"];

        public string SetWorkstation(string AMAccountName,string hosts)
        {
            zreturn zr = new zreturn();
            zr.AMAccountName = AMAccountName;
            zr.hosts = hosts;

            try
            {
                //不指定OU,我们对根作查询操作
                DirectoryEntry objDE = new DirectoryEntry(AD_LDAP + "/" + "DC=" + AD_DC1 + ",DC=" + AD_DC2, AD_admin, AD_password);
                
                //用户找出来           
                DirectorySearcher objSearcher = new DirectorySearcher(objDE, "(&(sAMAccountName=" + AMAccountName + "))");
                SearchResult one = objSearcher.FindOne();

                if (one != null)
                {
                    DirectoryEntry de = one.GetDirectoryEntry();
                    string oldws = Convert.ToString(de.Properties["userWorkstations"].Value); //注意这里null用convert
                    de.Properties["userWorkstations"].Value = hosts;
                    de.CommitChanges();                   
                  
                    zr.success = true;               
                    zr.oldws = oldws;
                    zr.newws = hosts;                   
                }
                else                 
                {   
                    zr.success = false;
                    zr.message = "The AMAccountName is not in this AD Server.";              
                }

            }
            catch (Exception ex)
            {             
                zr.success = false;                
                zr.message = ex.Message;            
            }

            log(JsonConvert.SerializeObject(zr));
            return JsonConvert.SerializeObject(zr);      
        }

        public void log(string s)
        {
            String line = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " " + s;          
            //日志处理(2/4)
            sw.WriteLine(line);
            //日志处理(3/4)
            sw.Flush(); //缓存区写文件
        }
    }

    public class zreturn
    {
        public string AMAccountName;
        public string hosts;
        public bool success;
        public string message;
        public string oldws;
        public string newws;

        public zreturn()
         {
            //构造函数对string类型赋初值
            foreach (var property in this.GetType().GetProperties())
                     {
                       if (property.PropertyType == typeof(string))
                            {
                            property.SetValue(this, string.Empty, null);
                             }
                    }
        }

}

 }