Windows 下腳本遠程管理數百臺蘋果系統

問題

今天同事的AD帳號頻繁被鎖,在DC的日誌上顯示源於無線網ISE的驗證失敗,ISE服務器的日誌顯示某個IP的設備的AD密碼錯誤。python

我把無線AP所在的範圍,這個設備的Mac地址給同事,問題來了,他轉了半個小時,愣是找不到對應的設備,也沒有人報告聯網不通。這個就很尷尬了~~shell

Windows 下腳本遠程管理數百臺蘋果系統

思路

怎麼找到對應的設備呢,由於無線網AD驗證沒經過,DHCP服務器沒有任何記錄。不少人同時打開WiFi和有線網,也許我能夠經過有線網去找這個無線網卡的地址。服務器

豆子想了一個笨辦法,首先經過Mac地址能夠判斷出這個是蘋果的網卡,那麼我遠程連到全部的蘋果系統上查詢對應的網卡應該有可能獲取到這個地址。session

想到了就作作吧。多線程

純屬練手,我用Python和Powershell都試了試。併發

Python 腳本

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

Windows 下腳本遠程管理數百臺蘋果系統

PowerShell 腳本

而後純屬無聊,我用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
}``

上面的腳本都能工做,不過代碼質量比較挫,以後有時間再慢慢優化。函數

相關文章
相關標籤/搜索