亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

AD帳戶操作C#示例代碼(一)——導入用戶信息

2019-11-14 16:44:56
字體:
來源:轉載
供稿:網友

    最近寫了一個AD帳戶導入的小工具(為啥寫作“帳”戶呢?),跟大家分享下相關代碼,歡迎各位高手指教!

    首先,我準備一個這樣的Excel文件作為導入模版,并添加了一些測試數據。

  

    然后,我打開Visual Studio 2012,新建一個Windows窗體應用程序。在主窗體界面,我放了一些Label、TextBox、Button控件,還有一個PRogressBar。

 

      開始寫代碼。首先寫從Excel里讀取數據的方法。

        private static async Task<DataTable> GetTableFromExcelAsync(string fileName)        {            return await Task.Factory.StartNew<DataTable>(() => GetTableFromExcel(fileName));        }        private static DataTable GetTableFromExcel(string fileName)        {            DataTable dataTable = new DataTable();            string connectionString = string.Format("Provider = Microsoft.ACE.OLEDB.12.0;Data Source ={0};Extended Properties='Excel 12.0 xml;HDR=YES'", fileName);            using (OleDbConnection oleDbConnection = new OleDbConnection(connectionString))            {                oleDbConnection.Open();                DataTable schemaTable = oleDbConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new Object[] { null, null, null, "TABLE" });                string sheetName = schemaTable.Rows[0].Field<string>("TABLE_NAME");                string commandText = string.Format("select * from [{0}]", sheetName);                using (OleDbDataAdapter adapter = new OleDbDataAdapter(commandText, oleDbConnection))                {                    adapter.Fill(dataTable);                }            }            return dataTable;        }


     這樣調用,將結果保存在一個DataTable里:

       private async void btnImport_Click(object sender, EventArgs e)       {            DataTable dataTable = await GetTableFromExcelAsync(txtUserListPath.Text);       }


     運行出現異常:“未在本地計算機上注冊 Microsoft.ACE.OLEDB.12.0 提供程序”。

 

      我的系統是X64的Windows 8 ,下載accessDatabaseEngine.exe安裝后,成功讀取數據。

      下載地址是:http://download.microsoft.com/download/7/0/3/703ffbcb-dc0c-4e19-b0da-1463960fdcdb/AccessDatabaseEngine.exe

      如果在發布時還發生異常,那么再試試屬性設置,把目標平臺(G)改成x86或勾選"首選32位(P)"。

      在.NET中訪問AD服務可以用DirectoryEntry類(引用程序集 :System.DirectoryServices(在 System.DirectoryServices.dll 中)、命名空間:  System.DirectoryServices)。

      創建DirectoryEntry對象要提供LDAP地址,作為我們創建用戶的根OU,當然還要有在這個OU下創建OU和帳戶的權限。

                string ldapPath = txtLdapPath.Text;                string userName = txtUserName.Text;                string passWord = txtPassword.Text; 

DirectoryEntry rootDirectoryEntry;
if (userName != string.Empty) { rootDirectoryEntry = new DirectoryEntry(ldapPath, userName, password); } else { rootDirectoryEntry = new DirectoryEntry(ldapPath); }

     DirectoryEntry 類使用參考:http://msdn.microsoft.com/zh-cn/library/z9cddzaa(v=vs.110).aspx

     在創建用戶帳戶前,要先創建它們依賴的上級OU。創建OU的代碼如下:

DirectoryEntry currentOuDirectoryEntry = currentOuDirectoryEntry.Children.Add("OU=" + currentValue, "organizationalUnit");currentOuDirectoryEntry.Properties["name"].Add(currentValue);currentOuDirectoryEntry.CommitChanges();

     創建用戶的代碼如下:

DirectoryEntry currentUserDirectoryEntry = currentOuDirectoryEntry.Children.Add("CN=" + displayName, "user");currentUserDirectoryEntry.Properties["sAMAccountName"].Value = sAMAccountName;currentUserDirectoryEntry.Properties["userPrincipalName"].Value = string.Format(@"{0}@{1}", sAMAccountName, domainName);currentUserDirectoryEntry.Properties["displayName"].Value = displayName;currentUserDirectoryEntry.CommitChanges();

     DirectoryEntry類的Properties屬性是一個集合,除了一些字符串類型的屬性,還有幾個我覺得操作比較麻煩的。

       例如"userAccountControl",看起來它只是一個整型字段,但是實際上它一個字段包含了很多個的狀態信息。每個狀態又對應著一個屬性標志(例如密碼永不過期是65536)。所以我們要從這一個userAccountControl字段讀取或寫入狀態要做次位運算。

        private void SetPropertyInUserAccountControl(DirectoryEntry directoryEntry, bool newValue, int propertyflag)        {            int userAccountControl = (int)directoryEntry.Properties["userAccountControl"].Value;            bool oldValue = GetPropertyFromUserAccountControl(directoryEntry, propertyflag);            if (oldValue != newValue)            {                if (newValue)                {                    directoryEntry.Properties["userAccountControl"].Value = userAccountControl | propertyflag;                }                else                {                    directoryEntry.Properties["userAccountControl"].Value = userAccountControl & ~propertyflag;                }            }        }        private bool GetPropertyFromUserAccountControl(DirectoryEntry directoryEntry, int propertyflag)        {            return Convert.ToBoolean((int)directoryEntry.Properties["userAccountControl"].Value & propertyflag);        }

       更多userAccountControl屬性標志(propertyflag參數)請參考資料:http://support.microsoft.com/kb/305144/zh-cn、http://msdn.microsoft.com/zh-cn/library/ms680832(VS.85).aspx。那么這些標志屬性是什么意思呢?為什么將"userAccountControl"值“&”一下屬性標志就可以得到對應的狀態呢?我把這些屬性標志轉換為二進制,發現都是只有一個1,其他都是0的。那個1的位置就是狀態的標志位,如果“userAccountControl”字段的這個位置是1,那么對應狀態就是“True”了。再用并運算(&:參考資料:http://msdn.microsoft.com/zh-cn/library/sbf85k1c.aspx)操作,因為0&0等于0,0&1或1&0也等于0,只有1&1才能等于1,所以“userAccountControl”和“只有一位是1其他全是0”的propertyflag并運算,就可以推斷出該狀態對應的標志位是不是1了。

    

      不過我十分討厭這種把多個維度的狀態保存在一個字段中的設計,在曾經的項目中我也遇到過有高人在關系數據庫中這樣設計表字段,但我個人覺得這不符合第一范式的設計(同一列有多個值,應該分為多個IsXX1,IsXX2的bit字段),另外狀態是個比較常用的過濾條件,在這個字段做位運算是否還能索引查找?當然有人覺得這樣做減少了字段數量(在UI顯示給用戶的時候還是要分開吧?不然誰看得懂?。€有就是設計這一個狀態字段以后想再多添加幾個狀態就不用修改表結構了。不過最重要的還是這樣設計能體現出設計者的高水平,因為初級的程序員、數學不好的程序員以及記憶力不好的程序員看到這樣一個整型值是不會馬上知道它代表什么——我就是這樣的程序員。

       不過還好,我們可以直接用幾個常用的,我創建的是正常帳戶,不需要禁用,所以userAccountControl直接給512。

       還有這些“System.__ComObject”類型的屬性,操作起來太不方便了。我在網上找了一些資料,通常是引用了一個“Interop.ActiveDs.dll”的文件(不清楚是誰寫的)。我這里只是希望新創建的用戶下次登錄時更改密碼就要寫:

currentUserDirectoryEntry.Properties["pwdLastSet"].Value = new LargeInteger() { HighPart = 0, LowPart = 0 };

      不過后來我不是用的上面代碼而是這樣寫的,也成功了。

currentUserDirectoryEntry.Properties["pwdLastSet"].Value = 0;

     關于ADSI 對象屬性有個參考資料:http://msdn.microsoft.com/zh-cn/library/ms180868(v=vs.90).aspx。

     我把幾個常用的字符串類型屬性寫在XML文件里,導入數據時直接賦值即可。

<userProperties>      <!--常規-->      <property name = "sn" title = "姓"/>      <property name = "givenName" title = "名"/>
 <property name = "initials" title = "英文縮寫"/> <property name = "displayName" title = "顯示名稱"/> <property name = "telephoneNumber" title = "電話號碼"/> <property name = "otherTelephone" title = "其它電話號碼"/> <property name = "mail" title = "電子郵件"/> <property name = "description" title = "描述"/> <property name = "physicalDeliveryOfficeName" title = "辦公室"/> <property name = "wWWHomePage" title = "網頁"/> <property name = "url" title = "其它網頁"/><!--地址--> <property name = "co" title = "國家/地區"/> <property name = "st" title = "省/自治區"/> <property name = "l" title = "市/縣"/> <property name = "streetAddress" title = "街道"/> <property name = "postOfficeBox" title = "郵政信箱"/> <property name = "postalCode" title = "郵政編碼"/><!--電話--> <property name = "homePhone" title = "家庭電話"/> <property name = "otherHomePhone" title = "其他家庭電話"/> <property name = "pager" title = "尋呼機"/> <property name = "otherPager" title = "其他尋呼機"/> <property name = "mobile" title = "移動電話"/> <property name = "otherMobile" title = "其他移動電話"/> <property name = "facsimileTelephoneNumber" title = "傳真"/> <property name = "otherFacsimileTelephoneNumber " title = "其他傳真"/> <property name = "ipPhone" title = "IP電話"/> <property name = "otherIpPhone" title = "其他IP電話"/> <property name = "info" title = "注釋"/><!--帳戶--> <property name = "userPrincipalName" title = "用戶登錄名"/> <property name = "sAMAccountName" title = "用戶登錄名(Windows 2000 以前版本)"/><!--組織--> <property name = "company" title = "公司"/> <property name = "department" title = "部門"/> <property name = "title" title = "職務"/> <property name = "manager" title = "經理"/> <property name = "directReports" title = "直接下屬"/> </userProperties>

    如果您一次性把這幾個屬性都提交了,還可能會出現一個很有個性的異常:“該服務器不愿意處理該請求”。

     要想讓“她”愿意,可以這樣寫:

using (DirectoryEntry currentUserDirectoryEntry = currentOuDirectoryEntry.Children.Add("CN=" + displayName, "user"))                            {                                currentUserDirectoryEntry.Properties["sAMAccountName"].Value = sAMAccountName;                                currentUserDirectoryEntry.Properties["userPrincipalName"].Value = string.Format(@"{0}@{1}", sAMAccountName, domainName);                                currentUserDirectoryEntry.Properties["displayName"].Value = displayName;                                currentUserDirectoryEntry.CommitChanges();                                currentUserDirectoryEntry.Properties["userAccountControl"].Value = userAccountControl;                                currentUserDirectoryEntry.Properties["pwdLastSet"].Value = 0;                                currentUserDirectoryEntry.Invoke("SetPassword", new object[] { newUserDefaultPassword });                                currentUserDirectoryEntry.CommitChanges();                            }

     因為我想給新導入的用戶一個初始的密碼,修改密碼的操作這樣寫就可以了:

currentUserDirectoryEntry.Invoke("SetPassword", new object[] { newUserDefaultPassword });

     當用戶是某個OU的管理員時,需要給它賦予權限。代碼里的ActiveDirectoryRights是個枚舉類型,當然您有時也會用到別的選擇。

                           if (string.Equals(currentDataRow[_isAdminColumnName] as string, @""))                            {                                IdentityReference newOwner = new NTAccount(domainName, sAMAccountName).Translate(typeof(SecurityIdentifier));                                ActiveDirectoryAccessRule newRule = new ActiveDirectoryAccessRule(newOwner, ActiveDirectoryRights.GenericAll, AccessControlType.Allow);                                currentOuDirectoryEntry.ObjectSecurity.SetAccessRule(newRule);                                currentOuDirectoryEntry.CommitChanges();                            }

     如果要導入的用戶已經存在,就會出現異常。那么如何判斷一個用戶是否已存在呢?這時我們需要用到的是.NET的DirectorySearcher類型。這個類型的一個構造方法需要給一個搜索根路徑、搜索篩選器、要檢索的屬性和搜索范圍。

 DirectorySearcher userDirectorySearcher = new DirectorySearcher(currentOuDirectoryEntry, string.Format(@"(&(cn={0})(objectCategory=person)(objectClass=user))", displayName), new[] { "adspath" }, SearchScope.OneLevel);
 SearchResult searchResult = userDirectorySearcher.FindOne();
 if (searchResult != null)
 {
//TODO:......
}

     DirectorySearcher 類使用參考:http://msdn.microsoft.com/zh-cn/library/System.DirectoryServices.DirectorySearcher(v=vs.90).aspx    

     最后將這些零散的代碼組合起來,就是我要做的工具了!

     看看導入的效果,算是成功導入了吧。

     當然這只是個很簡單的小例子,日后還要繼續完善,各位專家、高手如果看到我做的不好的地方也歡迎指正,多給些高大上的建議,非常感謝!

其他參考資料:

http://msdn.microsoft.com/en-us/library/aa367008(VS.85).aspx

http://msdn.microsoft.com/en-us/library/windows/desktop/ms675085(v=vs.85).aspx

AD用戶導入工具下載:

http://files.VEVb.com/CSharpDevelopers/ADUserImportTool.zip
    


上一篇:Web.config配置和節點介紹

下一篇:IOC

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久人体大胆视频| 国产午夜精品免费一区二区三区| 久久久久99精品久久久久| 久久亚洲综合国产精品99麻豆精品福利| 日日骚av一区| 日韩中文字幕在线看| 欧美日韩免费在线| 日韩美女主播视频| 韩国欧美亚洲国产| 亚洲人成在线观看| 亚洲已满18点击进入在线看片| 亚洲激情久久久| 久久久久久成人精品| 亚洲精品第一页| 国产va免费精品高清在线观看| 日韩欧美精品在线观看| 亚洲欧洲日产国产网站| 97成人精品区在线播放| 97国产精品人人爽人人做| 亚洲欧美国产日韩天堂区| 中文字幕在线国产精品| 欧美肥婆姓交大片| 午夜免费在线观看精品视频| 国产日韩欧美黄色| 亚洲人成电影网站色xx| 国产91精品青草社区| 国内外成人免费激情在线视频网站| 亚洲资源在线看| 国产日韩欧美黄色| 欧美一区二区色| 91久久国产婷婷一区二区| 亚洲天堂开心观看| 欧美超级乱淫片喷水| 17婷婷久久www| 中文字幕在线看视频国产欧美在线看完整| 久久色免费在线视频| 久久久久久噜噜噜久久久精品| 国产999在线观看| 欧美最猛性xxxxx(亚洲精品)| 中文字幕亚洲欧美| 国产精品久在线观看| 久久成人综合视频| 国产自产女人91一区在线观看| 久久影视电视剧免费网站| 中文字幕日韩av综合精品| 久久久久久国产免费| 欧美性高跟鞋xxxxhd| 国内外成人免费激情在线视频| 中文在线资源观看视频网站免费不卡| 国产精品久久久久久久久久久新郎| 九九综合九九综合| 欧洲成人午夜免费大片| 日本欧美黄网站| 欧美精品中文字幕一区| 久久成人在线视频| 欧美性xxxxxxxxx| 色综合天天综合网国产成人网| 97精品免费视频| 伦伦影院午夜日韩欧美限制| 伊人激情综合网| 久久97久久97精品免视看| 欧美激情成人在线视频| 亚洲电影在线看| 欧美成人性色生活仑片| 91系列在线观看| 久久久久久噜噜噜久久久精品| 亚洲欧美国产一区二区三区| 欧美成人h版在线观看| 国产亚洲一区二区精品| 欧美美最猛性xxxxxx| 国产精品伦子伦免费视频| 国产激情999| 欧美激情视频在线免费观看 欧美视频免费一| 亚洲成人精品视频在线观看| 精品美女国产在线| 国模吧一区二区三区| 久久久久久91香蕉国产| 国产成人综合精品在线| 欧美国产日本高清在线| 亚洲电影免费观看高清完整版| 国产成人av在线播放| 国产精品久久97| 国产精品嫩草影院久久久| 国产一区二区三区在线观看视频| 精品久久久久人成| 国产欧美在线播放| 国产精品视频久久| 欧美xxxx14xxxxx性爽| 高清欧美性猛交xxxx| 日本免费在线精品| 青青草99啪国产免费| 国产亚洲美女久久| 欧美性xxxx极品hd满灌| 国产精品久久久久91| 日韩在线精品一区| 亚洲精品中文字| 欧美成人激情视频| 亚洲四色影视在线观看| 国产视频自拍一区| 日韩精品极品在线观看播放免费视频| 国产成人高潮免费观看精品| 国产欧美日韩中文字幕| 精品中文视频在线| 92国产精品久久久久首页| 国产在线观看精品一区二区三区| 国产成人自拍视频在线观看| 欧美一级电影免费在线观看| 欧美中文字幕在线播放| 欧美日韩另类在线| 中文字幕在线精品| 日韩av有码在线| 亚洲aa在线观看| 亚洲视频精品在线| 福利一区视频在线观看| 91久久久久久久| 国产精品免费看久久久香蕉| 欧美激情久久久| 日韩精品中文字幕久久臀| 成人黄色短视频在线观看| 国语自产精品视频在线看一大j8| 久久综合免费视频| 国产精品一香蕉国产线看观看| 亚洲国产成人精品一区二区| 黄色成人av在线| 国产日韩欧美夫妻视频在线观看| 欧美丰满少妇xxxx| 欧美激情小视频| 亚洲黄色免费三级| 尤物九九久久国产精品的特点| 欧美午夜激情在线| 亚洲精品之草原avav久久| 日韩色av导航| 在线日韩第一页| 欧美激情亚洲视频| 韩曰欧美视频免费观看| 在线精品91av| 亚洲综合色激情五月| 国产女人精品视频| 国产女人18毛片水18精品| 国产精品自在线| 97在线免费观看| 日韩精品在线电影| 成人午夜在线观看| 午夜欧美不卡精品aaaaa| 高清欧美电影在线| 色偷偷av一区二区三区乱| 国产91露脸中文字幕在线| 久久久久久成人精品| 日韩精品丝袜在线| 日本伊人精品一区二区三区介绍| 91九色精品视频| 久久五月天色综合| 欧美成人免费网| 中文一区二区视频| 成人h片在线播放免费网站| 亚洲在线免费视频| 一区二区国产精品视频| 国产精品中文在线| 日韩精品在线电影| 亚洲一区二区中文字幕| 在线视频免费一区二区| 欧美激情亚洲激情| 日韩电影中文字幕在线观看| 亚洲精品网址在线观看|