第一个需求,登陆名称绑定计算机名( C#开发AD域控自动工具之四)
很快,我们迎来了第一个需求,OA新进员工流程中,需要域控:按员工号绑定工作站名称 。
功能设计如下:
1、 在AD域控服务器上部署自开发C# 中间件应用程序,调用微软提供的AD开发类库;实现对AD内元素(用户、OU等)的增删改查。
2、 对外使用WebService接口提供服务,调用该接口服务即可完成该操作。
3、AD域控中间件应用程序有详细的日志记录,对每一笔操作都记录到日志文件中。
泛微的OA通过WebService调用外部接口,这一块就交给小渔去搞定了。
一、我现在要在AD域控上摆一个WebService服务器出来,实现AD的操作。需要借助微软的WCF来开发:
在VS2017中建一个WCF服务
我们还是把使用配置文件,这样可以方便部署到服务器上不同的IP去,
为什么一定要部署到AD服务器上,因为对用户密码的修改,需要在服务器上调用类库,
所以一开始虽然需求没涉及到用户密码,但我还是一劳永逸的把中间件程序部署在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项目
项目中,我们引用启动刚才的DLL:
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才好。
----------2019-4-16下午加入了JSON消息返回---------------------------
全部代码:
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);
}
}
}
}
}