【逗老師帶你學IT】通過企業微信推送AD域密碼即將到期提醒

本文主要介紹,如何通過企業微信API向AD域賬號即將過期的用戶推送消息,以提醒用戶儘快修改密碼。
主要涉及技術點:

1、AD域控制器Dsquery命令
2、認識企業微信用戶信息JSON數據結構
3、Python JSON數據結構解釋和取值
4、Python 字典數據結構賦值取值
4、企業微信消息推送API接口的使用

一、獲取密碼即將過期的AD與賬號

1、先決條件

首先,你需要部署一臺AD域控制器。dsquery僅在DC和GC上運行有效,且可以是隻讀的DC或GC

2、關於DC和GC

DC:域控制器(Domain Controller)

在Windows Server系統中,域控制器(domain controller , DC)是一個在Windows服務器域中的接受安全認證請求(登錄, 檢查權限, 等)的服務器。是一臺裝有活動目服務的計算機(我們經常說到的DC服務器)

GC:全局編錄( Global Catalog)

包含森林中所有對象信息的特殊目錄數據庫

全局編錄是存儲林中所有 Active Directory 對象的副本的域控制器。全局編錄存儲林中主持域的目錄中所有對象的完全副本,以及林中所有其他域中所有對象的部分副本

全局編錄中包含的所有域對象的部分副本是用戶搜索操作中最常使用的部分。作爲其架構定義的一部分,這些屬性被標記爲包含到全局編錄中。在全局編錄中存儲所有域對象的最常搜索的屬性,可以爲用戶提供高效的搜索,而不會以不必要的域控制器參考影響網絡性能。

在林中的初始域控制器上,會自動創建全局編錄。可以向其他域控制器添加全局編錄功能,或者將全局編錄的默認位置更改到另一個域控制器上。

全局編錄允許用戶在林中的所有域中搜索目錄信息,而不論數據存儲在何處。執行林內的搜索時可獲得最大的速度並使用最小的網絡通信。

3、Dsquery命令

dsquery user -stalepwd 173 -o upn -limit 0

其中:
dsquery user表示查詢用戶
-stalepwd 173表示最後一次修改密碼時間>173天,假使密碼有效期180天,獲取7天后即將過期的賬號列表。
-o upn表示輸出格式爲upn
-limit 0指定傳回符合搜尋條件的對象數目,如果值是 0,將傳回所有符合的對象。如果不指定此參數,根據默認將只顯示前 100 個結果。

dsquery命令是AD域控管理中常用的一個查詢命令,更多詳細信息可以參考:
【逗老師帶你學IT】AD域控 Dsquery 查詢命令實例彙總
查詢出的結果如下圖所示,接下來我們要對這個信息進行處理,並轉換成企業微信的UserID:
在這裏插入圖片描述

二、企業微信用戶信息獲取和查詢

企業微信API文檔原文寫的很詳細,清晰,易懂。本文會直接註明各接口在開發者文檔中的位置,需要更多信息可以直接參考開發者文檔,原文鏈接如下:
企業微信開發文檔【服務端API】

1、企業微信API認證token獲取

接口說明

文檔位置:
開發指南>獲取access_token
獲取access_token是調用企業微信API接口的第一步,相當於創建了一個登錄憑證,其它的業務API接口,都需要依賴於access_token來鑑權調用者身份。
接口定義:
請求方式: GET(HTTPS)
請求地址: https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=ID&corpsecret=SECRET
注:此處標註大寫的單詞ID和SECRET,爲需要替換的變量,根據實際獲取值更新。其它接口也採用相同的標註,不再說明。

參數說明

參數 必須 說明
corpid 企業ID,獲取方式參考:術語說明-corpid
corpsecret 應用的憑證密鑰,獲取方式參考:術語說明-secret

返回結果示例

{
   "errcode": 0,
   "errmsg": "ok",
   "access_token": "accesstoken000001",
   "expires_in": 7200
}

Python代碼示例

CORPID="ww078964********a08b1"
CORPSECRET="EHH***********************19Kw"

def gettoken():
	try:
		headers = {"Content-Type": "text/plain"}
		request = requests.get(url="https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid="+CORPID+"&corpsecret="+CORPSECRET,headers=headers)
		request=json.loads(request.text)
		access_token=request['access_token']
		#提取JSON結構體中access_token字段值
	except Exception as err:
		raise err
	else:
		return access_token

Python數據結構-JSON取值

上面的Python示例中使用到了JSON數據結構的取值,Python自帶一個很方便的JSON解釋器,開局一句import json
之後

json_data=json.loads(JSON數據原文)
value=json_data['取值的字段名']

即可得到想要的字段的值
在這裏插入圖片描述

2、企業微信用戶信息查詢

2.1 讀取指定成員信息

接口說明

文檔位置:
通訊錄管理>成員管理>讀取成員
在通訊錄同步助手中此接口可以讀取企業通訊錄的所有成員信息,而自建應用可以讀取該應用設置的可見範圍內的成員信息。
接口定義:
請求方式: GET(HTTPS)
請求地址: https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&userid=USERID

參數說明

參數 必須 說明
access_token 調用接口憑證
userid 成員UserID。對應管理端的帳號,企業內必須唯一。不區分大小寫,長度爲1~64個字節

2.2 批量讀取部門成員信息,包括根部門(全員)

接口說明

文檔位置:
通訊錄管理>成員管理>獲取部門成員詳情
接口定義:
請求方式: GET(HTTPS)
請求地址: https://qyapi.weixin.qq.com/cgi-bin/user/list?access_token=ACCESS_TOKEN&department_id=DEPARTMENT_ID&fetch_child=FETCH_CHILD

參數說明

參數 必須 說明
access_token 調用接口憑證
department_id 獲取的部門id,根部門ID爲1
fetch_child 1/0:是否遞歸獲取子部門下面的成員

2.3 企業微信用戶信息JSON字段解釋

參數說明

參數 說明
errcode 返回碼
errmsg 對返回碼的文本描述內容
userlist 成員列表
userid 成員UserID。對應管理端的帳號
name 成員名稱,此字段從2019年12月30日起,對新創建第三方應用不再返回,2020年6月30日起,對所有歷史第三方應用不再返回,後續第三方僅通訊錄應用可獲取,第三方頁面需要通過通訊錄展示組件來展示名字
mobile 手機號碼,第三方僅通訊錄應用可獲取
department 成員所屬部門id列表,僅返回該應用有查看權限的部門id
order 部門內的排序值,32位整數,默認爲0。數量必須和department一致,數值越大排序越前面。
position 職務信息;第三方僅通訊錄應用可獲取
gender 性別。0表示未定義,1表示男性,2表示女性
email 郵箱,第三方僅通訊錄應用可獲取
is_leader_in_dept 表示在所在的部門內是否爲上級;第三方僅通訊錄應用可獲取
avatar 頭像url。第三方僅通訊錄應用可獲取
thumb_avatar 頭像縮略圖url。第三方僅通訊錄應用可獲取
telephone 座機。第三方僅通訊錄應用可獲取
alias 別名;第三方僅通訊錄應用可獲取
status 激活狀態: 1=已激活,2=已禁用,4=未激活,5=退出企業。已激活代表已激活企業微信或已關注微工作臺(原企業號)。未激活代表既未激活企業微信又未關注微工作臺(原企業號)。
extattr 擴展屬性,第三方僅通訊錄應用可獲取
qr_code 員工個人二維碼,掃描可添加爲外部聯繫人;第三方僅通訊錄應用可獲取
external_profile 成員對外屬性,字段詳情見對外屬性;第三方僅通訊錄應用可獲取
external_position 對外職務。 第三方僅通訊錄應用可獲取
address 地址,第三方僅通訊錄應用可獲取
hide_mobile 是否隱藏手機號
english_name 英文名
open_userid 全局唯一。對於同一個服務商,不同應用獲取到企業內同一個成員的open_userid是相同的,最多64個字節。僅第三方應用可獲取
main_department 主部門

返回結果示例:

需要注意的是,之後我們通過推送信息API發送消息的時候,用戶信息UserID字段與AD域控中的email或者CN Name字段大概率是不同的。在本例中,僅email字段可以做到完全一致。因此,我們的思路是,通過email查找企業微信用戶的UserID,並使用該UserID向用戶發送信息。

{
    "errcode": 0,
    "errmsg": "ok",
    "userlist": [{
        "userid": "zhangsan",
        "name": "李四",
        "department": [1, 2],
        "order": [1, 2],
        "position": "後臺工程師",
        "mobile": "13800000000",
        "gender": "1",
        "email": "[email protected]",
        "is_leader_in_dept": [1, 0],
        "avatar": "http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/0",
        "thumb_avatar": "http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/100",
        "telephone": "020-123456",
        "alias": "jackzhang",
        "status": 1,
        "address": "廣州市海珠區新港中路",
        "hide_mobile" : 0,
        "english_name" : "jacky",
        "open_userid": "xxxxxx",
        "main_department": 1,
        "extattr": {
            "attrs": [
                {
                    "type": 0,
                    "name": "文本名稱",
                    "text": {
                        "value": "文本"
                    }
                },
                {
                    "type": 1,
                    "name": "網頁名稱",
                    "web": {
                        "url": "http://www.test.com",
                        "title": "標題"
                    }
                }
            ]
        },
        "qr_code": "https://open.work.weixin.qq.com/wwopen/userQRCode?vcode=xxx",
        "external_position": "產品經理",
        "external_profile": {
            "external_corp_name": "企業簡稱",
            "external_attr": [{
                    "type": 0,
                    "name": "文本名稱",
                    "text": {
                        "value": "文本"
                    }
                },
                {
                    "type": 1,
                    "name": "網頁名稱",
                    "web": {
                        "url": "http://www.test.com",
                        "title": "標題"
                    }
                },
                {
                    "type": 2,
                    "name": "測試app",
                    "miniprogram": {
                        "appid": "wx8bd80126147dFAKE",
                        "pagepath": "/index",
                        "title": "miniprogram"
                    }
                }
            ]
        }
    }]
}

Python代碼示例:

def user_dict(access_token):
	try:
		user_dict=dict()
		headers = {"Content-Type": "text/plain"}
		request = requests.get(url="https://qyapi.weixin.qq.com/cgi-bin/user/list?access_token="+access_token+"&department_id=1&fetch_child=1",headers=headers)
		request=json.loads(request.text)
		all_user_list=request['userlist']
		for user in all_user_list:
			#敲黑板,此處用到二級JSON取值
			userid=user['userid']
			username=user['name']
			email=user['email']
			email_fix=email.find("@")
			CNname=email[:email_fix]
			user_dict[CNname]=[userid,username,email]
	except Exception as err:
		raise err
	else:
		return user_dict
		#返回一個字典格式的結構體,字典內嵌一個list,結構示例如下:
		'CNname(郵箱前綴)': ['userid', 'username', 'email']
		'zhaoxy12149': ['ZhaoXiaoYun', '花和尚', '[email protected]']

Python數據結構-字典賦值(添加、修改記錄)

上面的Python示例中使用到了字典的賦值,字典數據結構對於大量的記錄可以快速進行查找,避免使用list等結構查找數據時需要頻繁的for循環。
user_dict=dict()語句使用dict()創建一個空的字典
對於添加、修改已有記錄,直接對字典的主鍵賦值即可。主鍵已經存在則會修改已有記錄,主鍵不存在則會創建新的記錄。

user_dict[’AAA‘]='AAA_Value'

在這裏插入圖片描述
注意,字典中記錄的值,可以是字符串,也可以是list等其他數據結構。非常靈活。

2.4 通過AD域賬戶查詢企業微信UserID

Python代碼示例

#輸入CNname爲郵箱前綴格式
def userid(user_dict,CNname):
	try:
		get_userid=get_username=get_email='N/A'
		get_userid=user_dict[CNname][0]
		get_username=user_dict[CNname][1]
		get_email=user_dict[CNname][2]
		#字典的value爲一個list,分別獲取list的0、1、2號元素
	except Exception as err:
		print("Get userid failed with CNname:"+CNname)
		raise err
	else:
		return get_userid,get_username,get_email

Python數據結構-字典取值

上面的Python示例中使用到了字典數據結構的取值
對於字典的數據結構,假使有如下字典:
person = {‘name’:‘xiaoming’, ‘age’:18}
最簡單的一種方式:
person['name']即可得到name的value,值爲“xiaoming”
另外一種方式:
person.get('name')也可以得到name的value。
兩種方式的區別爲,第一種如果鍵查不到拋異常,第二種查不到賦值爲空,第二種方式也可以設置返回默認值。
在這裏插入圖片描述

三、企業微信應用消息推送

1、企業微信應用消息推送

1.1 調用應用消息推送接口

接口說明

文檔位置:
消息推送>發送應用消息
應用支持推送文本、圖片、視頻、文件、圖文等類型。
接口定義:
請求方式: POST(HTTPS)
請求地址: https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN

參數說明

參數 必須 說明
access_token 調用接口憑證

1.2 發送請求內容

企業微信消息推送支持推送以下格式的消息:

文本消息
圖片消息
語音消息
視頻消息
文件消息
文本卡片消息
圖文消息
圖文消息(mpnews)
markdown消息
小程序通知消息
任務卡片消息

發送請求示例

{
   "touser" : "UserID1|UserID2|UserID3",
   "toparty" : "PartyID1|PartyID2",
   "totag" : "TagID1 | TagID2",
   "msgtype" : "text",
   "agentid" : 1,
   "text" : {
       "content" : "你的快遞已到,請攜帶工卡前往郵件中心領取。\n出發前可查看<a href=\"http://work.weixin.qq.com\">郵件中心視頻實況</a>,聰明避開排隊。"
   },
   "safe":0,
   "enable_id_trans": 0,
   "enable_duplicate_check": 0,
   "duplicate_check_interval": 1800
}

參數說明

參數 必須 說明
touser 指定接收消息的成員,成員ID列表(多個接收者用‘|’分隔,最多支持1000個)。特殊情況:指定爲@all”,則向該企業應用的全部成員發送
toparty 指定接收消息的部門,部門ID列表,多個接收者用‘|’分隔,最多支持100個。當touser爲”@all”時忽略本參數
totag 指定接收消息的標籤,標籤ID列表,多個接收者用‘|’分隔,最多支持100個。當touser爲”@all”時忽略本參數
agentid 企業應用的id,整型。企業內部開發,可在應用的設置頁面查看查看方式;第三方服務商,可通過接口獲取企業授權信息獲取該參數值.

touser、toparty、totag不能同時爲空,後面不再強調。

Python代碼示例

以下爲一個markdown格式的請求代碼示例

class post:
	def message(access_token,agentid,userid,username):
		try:
			headers = {"Content-Type": "text/plain"}
			data={
			"touser" : userid,
			"msgtype": "markdown",
			"agentid" : agentid,
			"markdown": {
					"content": '''**<font color="warning">【重要提示】</font>**
					>親愛的**'''+username+'''**,您好:
					>
					>您的域賬號密碼即將過期,域賬號密碼有效期爲180天
					>
					>請及時訪問[**erp.csdn.com**](https://erp.csdn.com/Password.html)修改您的域賬號密碼。
					>
					>密碼過期未修改會導致您無法連接集團WIFI,VPN,以及無法登陸各種業務系統!
					>
					>忘記域賬號密碼,請通過以下路徑自助重置:
					>**ERP系統->新建申請->自助賬號密碼重置->AD域密碼重置**'''
			},
			"enable_duplicate_check": 0,
			"duplicate_check_interval": 1800
			}
			request = requests.post(url="https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token="+access_token,headers=headers,json=data)
		except Exception as err:
			raise err
		else:
			return request.text

消息效果:
在這裏插入圖片描述

四、Python代碼全文

import json
import requests
import os

CORPID="ww0******08b1"
AGENTID="1*******2"
CORPSECRET="EHHs2FC********************DHDJ19Kw"

def read_file_as_str(file_path):
	# 判斷路徑文件存在
	if not os.path.isfile(file_path):
		raise TypeError(file_path + " does not exist")
	
	all_the_text = open(file_path).read()
	# print type(all_the_text)
	return all_the_text
	

def gettoken():
	try:
		headers = {"Content-Type": "text/plain"}
		request = requests.get(url="https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid="+CORPID+"&corpsecret="+CORPSECRET,headers=headers)
		request=json.loads(request.text)
		access_token=request['access_token']
	except Exception as err:
		raise err
	else:
		return access_token

class weixin:
	class get:
		def userid(user_dict,CNname):
			try:
				get_userid=get_username=get_email='N/A'
				get_userid=user_dict[CNname][0]
				get_username=user_dict[CNname][1]
				get_email=user_dict[CNname][2]
			except Exception as err:
				print("Get userid failed with CNname:"+CNname)
				raise err
			else:
				return get_userid,get_username,get_email
			
		def userinfo_verbose(access_token,userid):
			try:
				headers = {"Content-Type": "text/plain"}
				request = requests.get(url="https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token="+access_token+"&userid="+userid,headers=headers)
			except Exception as err:
				raise err
			else:
				return request.text
				
		def user_dict(access_token):
			try:
				user_dict=dict()
				headers = {"Content-Type": "text/plain"}
				request = requests.get(url="https://qyapi.weixin.qq.com/cgi-bin/user/list?access_token="+access_token+"&department_id=1&fetch_child=1",headers=headers)
				request=json.loads(request.text)
				all_user_list=request['userlist']
				for user in all_user_list:
					userid=user['userid']
					username=user['name']
					email=user['email']
					email_fix=email.find("@")
					CNname=email[:email_fix]
					user_dict[CNname]=[userid,username,email]
			except Exception as err:
				raise err
			else:
				return user_dict
				
			
	class post:
		def message(access_token,agentid,userid,username):
			try:
				headers = {"Content-Type": "text/plain"}
				data={
				"touser" : userid,
				"msgtype": "markdown",
				"agentid" : agentid,
				"markdown": {
						"content": '''**<font color="warning">【重要提示】</font>**
					>親愛的**'''+username+'''**,您好:
					>
					>您的域賬號密碼即將過期,域賬號密碼有效期爲180天
					>
					>請及時訪問[**erp.csdn.com**](https://erp.csdn.com/Password.html)修改您的域賬號密碼。
					>
					>密碼過期未修改會導致您無法連接集團WIFI,VPN,以及無法登陸各種業務系統!
					>
					>忘記域賬號密碼,請通過以下路徑自助重置:
					>**ERP系統->新建申請->自助賬號密碼重置->AD域密碼重置**'''
				},
				"enable_duplicate_check": 0,
				"duplicate_check_interval": 1800
				}
				request = requests.post(url="https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token="+access_token,headers=headers,json=data)
			except Exception as err:
				raise err
			else:
				return request.text

def main():
	try:
		command=os.popen("dsquery user -stalepwd 173 -o upn -limit 0")
		#使用OS功能調用Windows系統命令行
		user_list_file=command.read()
		#讀取OS系統命令行的回顯
		user_list_file=user_list_file.replace('""\n','').replace('"','').replace('@csdn.com','')
		sent_user_list=user_list_file.split("\n")
		#將原始數據格式化成list結構
		access_token=gettoken()
		#獲取access_token
		user_dict=weixin.get.user_dict(access_token)
		#讀取全員信息
		for i in range(len(sent_user_list)-1):
			try:
				userid,username,email=weixin.get.userid(user_dict,sent_user_list[i])
			except Exception as err:
				print(err)
			else:
				print(userid,username,email)
				sent_result=weixin.post.message(access_token,AGENTID,userid,username)
		
	except Exception as err:
		print(err)


if __name__ == '__main__':
	main()

往期回顧:
【逗老師帶你學IT】Google Admin服務賬號+API管理G suit內所有網域用戶
【逗老師帶你學IT】PRTG監控系統通過企業微信推送圖文混排告警消息
【逗老師帶你學IT】PRTG HTTP API獲取指定傳感器流量圖表圖片
【逗老師帶你學IT】PRTG監控系統合併多個傳感器通道數據
【逗老師帶你學IT】PRTG監控系統通過企業微信推送告警消息
【逗老師帶你學IT】PRTG監控系統配合樹莓派採集企業內部無線網絡質量
【逗老師帶你學IT】vMware ESXi 6.7合併第三方硬件驅動
【逗老師帶你學IT】Kiwi Syslog Server安裝和配置教程
【逗老師帶你學IT】Kiwi Syslog Web Access與Active Directory集成認證
【逗老師帶你學IT】vMware ESXi 6.7合併第三方硬件驅動
【逗老師帶你學IT】Windows Server Network Policy Service(NPS)記賬與審計
【逗老師帶你學IT】Windows Server NPS服務構建基於AD域控的radius認證
【逗老師帶你學IT】AD域控和freeradius集成認證環境,PAP,MSCHAPV2
【逗老師帶你學IT】深信服SSL遠程接入與深信服行爲審計同步登陸用戶信息

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章