今天同事的AD帐号频繁被锁,在DC的日志上显示源于无线网ISE的验证失败,ISE服务器的日志显示某个IP的设备的AD密码错误。python
我把无线AP所在的范围,这个设备的Mac地址给同事,问题来了,他转了半个小时,愣是找不到对应的设备,也没有人报告联网不通。这个就很尴尬了~~shell
怎么找到对应的设备呢,由于无线网AD验证没经过,DHCP服务器没有任何记录。不少人同时打开WiFi和有线网,也许我能够经过有线网去找这个无线网卡的地址。服务器
豆子想了一个笨办法,首先经过Mac地址能够判断出这个是苹果的网卡,那么我远程连到全部的苹果系统上查询对应的网卡应该有可能获取到这个地址。session
想到了就作作吧。多线程
纯属练手,我用Python和Powershell都试了试。并发
Python我曾经写过一个模仿fabric的程序,能够远程的对多台Linux或者OSX机器执行远程操做,上传和下载。基本上就是调用threading, paramiko,queue几个模块。app
#!/usr/bin/env python # -*- coding:utf-8 -*- # Author Yuan Li """ 本程序模拟Fabric,远程的批量进行SSH链接,能够执行下载,上传和shell命令执行。 远程命令的执行,使用了线程池的技术,由于执行的时间比较少,而线程自己执行的时间占的比重比较大; 对于下载和上传,由于自己就是比较消耗时间的操做,所以每一个链接单独使用了线程建立和销毁,由于时间比较久,线程的时间能够忽略了 """ import threading import queue import time import paramiko import os #找到相对路径 parent_path = os.path.abspath(os.pardir) db_path=os.path.join(parent_path,'db') #一个管理类,基本思路是把任务和相关的参数填充到队列(任务池)中,而后建立一个进程池,里面的进程循环地读取任务池里面的内容,任何执行其中的内容,直到全部任务所有实现。 class workmanager(object): #构造函数 def __init__(self,cmd,username,password,work_num=1000,thread_num=2,): """ :param cmd:远程命令 :param username: 用户名 :param password: 密码 :param work_num: 任务池(队列大小) :param thread_num: 线程池大小 """ self.cmd=cmd self.work_num=work_num self.thread_num=thread_num self.queue=queue.Queue() self.threads=[] self.init_task(work_num,cmd,username,password) self.init_threadpool(thread_num) #初始化任务池 def init_task(self,num,inp,username,password): for i in range(num): self.add_job(do_job,i,inp,username,password) #添加任务到任务池 def add_job(self,job,*args): #填充任务到任务池,每个任务是一个元祖(任务,参数列表) self.queue.put((job,list(args))) #初始化线程池 def init_threadpool(self,num): for i in range(num): self.threads.append(work(self.queue)) #等待挂起主线程 def wait_allcomplete(self): for item in self.threads: if item.isAlive(): item.join() #线程类,每一个线程循环地去任务池取任务 class work(threading.Thread): def __init__(self,que): super(work, self).__init__() self.queue=que self.start() def run(self): while True: try: #当任务池为空的时候,强制报错,退出 do,args=self.queue.get(block=False) # print(do,args) do(args[0],args[1],args[2],args[3]) #确保队列里面的任务都完成了 self.queue.task_done() except: break #初始化的一个主机组,测试用的 hosts=['anoble-ise','bberry-ise','blackbr-ise','jlau-ise','kwood-ise','marwa-ise','smaroo-ise','psekarwin-ise','spare2-ise'] #远程链接SSH而且执行命令 def do_job(args,inp,username,password): """ :param args: hosts列表的索引 :param inp: 远程命令 :param username: 用户名 :param password: 密码 :return: """ # time.sleep(0.1) ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(hosts[args], 22, username, password) # 执行命令测试 stdin, stdout, stderr = ssh.exec_command(inp) for line in stdout.readlines(): print(line.strip()) print(("\x1b[5;19;32m %s \x1b[0m" % hosts[args]).center(40,'*')) print("\n") #下载测试 def download(args,user,pwd,remote,local): """ :param args: hosts列表的索引 :param inp: 远程命令 :param username: 用户名 :param password: 密码 :return: """ try: # print(hosts[args]) t = paramiko.Transport((hosts[args],22)) t.connect(username=user, password=pwd) sftp = paramiko.SFTPClient.from_transport(t) # remotepath='/tmp/test2' if not os.path.isdir(local): os.makedirs(local) remotepath=remote localpath=os.path.join(local,hosts[args]) sftp.get(remotepath, localpath) print("下载文件从%s成功" % hosts[args]) except Exception as ex: print("下载文件从%s失败"%hosts[args]) # 上传测试 def upload(args,user,pwd,remote,local): try: # print(hosts[args]) t = paramiko.Transport((hosts[args], 22)) t.connect(username=user, password=pwd) sftp = paramiko.SFTPClient.from_transport(t) # remotepath='/tmp/test2' remotepath=remote localpath=local # localpath='c:/temp/aaa.txt' sftp.put(localpath, remotepath) print('上传文件到%s成功' % hosts[args]) t.close() except Exception as ex: print('上传文件到%s失败'%hosts[args]) #选择主机组 def hostinfo(): global hosts print("可供选择的主机组包括:") from os import listdir from os.path import isfile, join # mypath=os.getcwd() onlyfiles = [f for f in listdir(db_path) if isfile(join(db_path, f))] print(onlyfiles) for file in onlyfiles: file_path=os.path.join(db_path,file) with open(file_path,'r') as fp: print(("\x1b[5;19;32m %s 主机列表 \x1b[0m" %file).center(40, '*')) for line in fp: print(line.strip()) name=input("请选择你要操做的主机组名称(hostgroup1,hostgroup2,hostgroup3..)") if name in onlyfiles: hosts=[] file_path=os.path.join(db_path,name) with open(file_path,'r') as fp: for line in fp: hosts.append(line.strip()) else: print("该主机组不存在") username="" password="" #入口文件 def display(): global hosts,username,password msg=""" 欢迎使用Fabric模拟程序,您能够执行如下操做 1.显示主机组 2.批量执行远程命令 3.批量上传 4.批量下载 5.输入管理员帐号 6.退出 """ msg2 = """ 1.选择主机组 2.列出当前主机列表 3.返回上一级目录 """ while True: print(msg) inpt=input("请输入选项") #输出主机组的相关信息 if inpt=='1': while True: print(msg2) opt=input("请输入选项") if opt=='1': hostinfo() elif opt=='2': for item in hosts: print(item) elif opt=='3':break else:print("非法输入") #远程批量操做 elif inpt=='2': # username=input("用户名") # password=input("密码") if not username: print("请先配置登陆帐号信息") else: while True: inp = input("输入指令(q返回上级目录)\n>>>") if inp =='q':break if not inp: print("不能输入空命令") else: start = time.time() #指定命令,用户名,密码,任务池(队列)的大小,和线程的个数) work_manager = workmanager(inp,username,password, len(hosts), 20) work_manager.wait_allcomplete() end = time.time() print("Cost time is %s" % (end - start)) #建立批量上传的多线程 elif inpt=='3': if not username: print("请先配置登陆帐号信息") else: remote_path=input("远程路径") local_path=input("当前路径") threads = [] for item in range(len(hosts)): t = threading.Thread(target=upload, args=(item,username,password,remote_path,local_path)) t.start() threads.append(t) for t in threads: t.join() #建立批量下载的多线程 elif inpt=='4': if not username: print("请先配置登陆帐号信息") else: remote_path = input("远程文件路径") local_path = input("当前文件夹路径") threads=[] for item in range(len(hosts)): t = threading.Thread(target=download, args=(item,username,password,remote_path,local_path)) t.start() threads.append(t) for t in threads: t.join() elif inpt=='5': username = input("用户名") password = input("密码") elif inpt=='6': exit("退出程序") else: print("无效输入,请重试") if __name__ == '__main__': display()
跑起来界面大概是这样的ssh
而后纯属无聊,我用Powershell也简单的实现了一次。Powershell主要是用第三方模块 posh-ssh进行链接。这个模块自己没有提供多线程的功能,这里偷懒,豆子也没用runspace(多线程),也没写异常处理,就想看看是否工做。所以他链接session的时候不是并发操做,而是挨个执行,花了可能10分钟才和几百个苹果客户端创建了ssh session,比起上面的Python脚本慢不少。ide
#先找到全部的苹果系统,排除ping不通的 $sydmac=Get-ADComputer -Filter {operatingsystem -like '*MAC*'} -Properties ipv4address | Where-Object {$_.ipv4address -notlike ''} $sydmac| select -expand dnshostname |Invoke-Parallel -ScriptBlock {Test-Connection -ComputerName "$_" -Count 1 -ErrorAction SilentlyContinue -ErrorVariable err | select Ipv4address, @{n='DNS';e={[System.Net.Dns]::gethostentry($_.ipv4address).hostname}}} -Throttle 20 | select -ExpandProperty dns| out-file c:\temp\mac.txt $list=gc C:\temp\mac.txt Import-Module posh-ssh #密码帐号 $username = "administrator" $secureStringPwd = ConvertTo-SecureString -AsPlainText "111222333" -Force $creds = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $secureStringPwd #这里循环写的很low 很慢,和每一个客户端分别创建session,稍后有空改为队列+runspace的多线程试试 foreach($line in $list){ New-SSHSession -ComputerName $line -Credential ( get-credential $creds ) -AcceptKey } $sessions=Get-SSHSession for($i=0;$i -lt $sessions.Length;$i++){ Invoke-SSHCommand -Command 'ifconfig | grep ether' -Sessionid $i -ErrorAction SilentlyContinue }``
上面的脚本都能工做,不过代码质量比较挫,以后有时间再慢慢优化。函数