1. 程式人生 > >python 實現微信遠端控制喚醒內網機器和遠端關閉windows 主機!

python 實現微信遠端控制喚醒內網機器和遠端關閉windows 主機!

python 實現微信遠端控制喚醒內網機器和遠端關閉windows 主機!

準備工作

本程式,主要是實現遠端管理 Windows10作業系統的開機和關機:

進群進群:943752371可以獲取Python各類入門學習資料!

這是我的微信公眾號【Python程式設計之家】各位大佬用空可以關注下,每天更新Python學習方法,感謝!

111111111111.png

1.在 Windows機器的相同內網中放一個 linux 主機,我這裡用樹莓派代替,如果你是用 openwrt 之類的路由器也可以。

2.linux 主機需要能夠遠端訪問,我這裡是有 frp 將樹莓派的埠對映到我的公網 linux 主機上。所以可以隨時遠端 ssh 過去。

3.Windows 機器的網絡卡必須是有線連線,支援網路喚醒功能。

開機實現思路

首先通過微信傳送開機指令,這裡我使用的是 itchat 程式會呼叫 paramiko 庫去ssh 遠端到內網的樹莓派執行 wakeonlan 命令去喚醒 Windows 主機。

<pre style="-webkit-tap-highlight-color: transparent; box-sizing: border-box; font-family: Consolas, Menlo, Courier, monospace; font-size: 16px; white-space: pre-wrap; position: relative; line-height: 1.5; color: rgb(153, 153, 153); margin: 1em 0px; padding: 12px 10px; background: rgb(244, 245, 246); border: 1px solid rgb(232, 232, 232); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

[email protected]:~ $ wakeonlan -i 192.168.1.0 14:dd:a9:ea:0b:96
Sending magic packet to 192.168.1.0:9 with 14:dd:a9:ea:0b:96
</pre>

接下來,程式會通過 icmp 協議,也就是 ping 下需要喚醒的目標主機然後過濾下,一個正常的 icmp 包是64位元組,過濾打印出這個64

例如 ping 百度

<pre style="-webkit-tap-highlight-color: transparent; box-sizing: border-box; font-family: Consolas, Menlo, Courier, monospace; font-size: 16px; white-space: pre-wrap; position: relative; line-height: 1.5; color: rgb(153, 153, 153); margin: 1em 0px; padding: 12px 10px; background: rgb(244, 245, 246); border: 1px solid rgb(232, 232, 232); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">➜ ~ ping 

www.baidu.com
PING www.a.shifen.com (180.97.33.108): 56 data bytes
64 bytes from 180.97.33.108: icmp_seq=0 ttl=53 time=8.865 ms
64 bytes from 180.97.33.108: icmp_seq=1 ttl=53 time=9.206 ms
64 bytes from 180.97.33.108: icmp_seq=2 ttl=53 time=8.246 ms
</pre>

我這裡用一段 linux 命令去過濾是否有64,這裡為啥要用 head -n 1 呢,因為有可能會出現2行,經過測試,我們只需要取64這個值就可以了

<pre style="-webkit-tap-highlight-color: transparent; box-sizing: border-box; font-family: Consolas, Menlo, Courier, monospace; font-size: 16px; white-space: pre-wrap; position: relative; line-height: 1.5; color: rgb(153, 153, 153); margin: 1em 0px; padding: 12px 10px; background: rgb(244, 245, 246); border: 1px solid rgb(232, 232, 232); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">ping 192.168.1.182 -c 1 | grep 64 | cut -d " " -f 1|head -n 1
</pre>

如果有則表示開機成功已經聯網了,返回開機成功,否則程式繼續往下走,去喚醒,然後在 ping 一次確認是否開機,如果為是則返回開機成功,否則返回失敗。程式執行成功後,在我的網站根目錄建立一個 shutdown 檔案,用於後面的關機操作

<pre style="-webkit-tap-highlight-color: transparent; box-sizing: border-box; font-family: Consolas, Menlo, Courier, monospace; font-size: 16px; white-space: pre-wrap; position: relative; line-height: 1.5; color: rgb(153, 153, 153); margin: 1em 0px; padding: 12px 10px; background: rgb(244, 245, 246); border: 1px solid rgb(232, 232, 232); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">#!/usr/bin/python

-- coding: utf-8 --

import itchat
import paramiko
import os
import time
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
hostname = ''
username = ''
port =
key_file = '/home/fangwenjun/.ssh/id_rsa'
filename = '/home/fangwenjun/.ssh/known_hosts'
@itchat.msg_register(itchat.content.TEXT)
def text_reply(msg):
if msg['ToUserName'] != 'filehelper': return
if msg['Text'] == u'開機':
paramiko.util.log_to_file('ssh_key-login.log')
privatekey = os.path.expanduser(key_file)
try:
key = paramiko.RSAKey.from_private_key_file(privatekey)
except paramiko.PasswordRequiredException:
key = paramiko.RSAKey.from_private_key_file(privatekey,key_file_pwd)
ssh = paramiko.SSHClient()
ssh.load_system_host_keys(filename=filename)
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname=hostname,username=username,pkey=key,port=port)

執行喚醒命令

stdin,stdout,stderr=ssh.exec_command('ping 192.168.1.182 -c 1 | grep 64 | cut -d " " -f 1|head -n 1')
sshCheckOpen = stdout.read()
sshCheckOpen =sshCheckOpen.strip('
')
print type(sshCheckOpen)
print sshCheckOpen

進行判斷,如果為64,則說明 ping 成功,說明裝置已經在開機狀態,程式結束,否則執行喚醒

if sshCheckOpen == '64':
connect_ok_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
itchat.send(connect_ok_time+u'裝置已經開機', toUserName='filehelper')
else:
ssh_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
itchat.send(ssh_time+u'開始連線遠端主機', toUserName='filehelper')
stdin,stdout,stderr=ssh.exec_command('wakeonlan -i 192.168.1.0 14:dd:a9:ea:0b:96')
wakeonlan_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
itchat.send(wakeonlan_time+u'執行喚醒,等待裝置開機聯網', toUserName='filehelper')

由於開機需要一些時間去啟動網路,所以這裡等等60s

time.sleep(60)

執行 ping 命令,-c 1 表示只 ping 一下,然後過濾有沒有64,如果有則獲取64傳給sshConStatus

stdin,stdout,stderr=ssh.exec_command('ping 192.168.1.182 -c 1 | grep 64 | cut -d " " -f 1|head -n 1')
sshConStatus = stdout.read()
sshConStatus =sshConStatus.strip('
')
print type(sshConStatus)
print sshConStatus

進行判斷,如果為64,則說明 ping 成功,裝置已經聯網,可以進行遠端連線了,否則傳送失敗訊息

if sshConStatus == '64':
connect_ok_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
itchat.send(connect_ok_time+u'裝置喚醒成功,您可以遠端連線了', toUserName='filehelper')
else:
connect_err_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
itchat.send(connect_err_time+u'裝置喚醒失敗,請檢查裝置是否連線電源', toUserName='filehelper')
ssh.close()

在網站根目錄建立一個空檔案,命名為 shutdown

os.system('touch /www/shutdown')
print '執行開機訊息成功'
</pre>

python 實現微信遠端控制喚醒內網機器和遠端關閉windows 主機!

關機部分實現

當接收關機指令時,程式會去刪除網站根目錄的 shutdown 檔案,客戶端我寫了幾行程式碼,去通過 requests 庫每隔30s 傳送 http head 請求去判斷檔案是否是404,如果是404 這說明檔案不存在,呼叫系統關機操作,執行關機,然後還是 ssh 到樹莓派去 ping 目標主機,如果返回為空,則說明關機成功,否則關機失敗。這只是針對 Windows 的關機,如果目標主機是 linux 則簡單多了。

<pre style="-webkit-tap-highlight-color: transparent; box-sizing: border-box; font-family: Consolas, Menlo, Courier, monospace; font-size: 16px; white-space: pre-wrap; position: relative; line-height: 1.5; color: rgb(153, 153, 153); margin: 1em 0px; padding: 12px 10px; background: rgb(244, 245, 246); border: 1px solid rgb(232, 232, 232); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">if msg['Text'] == u'關機':

刪除網站根目錄的shutdown 檔案

rmfile = os.system('rm -rf /www/shutdown')
if rmfile == 0:
print '執行關機訊息成功'
shutdown_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
itchat.send(shutdown_time+u'正在關機....', toUserName='filehelper')
paramiko.util.log_to_file('ssh_key-login.log')
privatekey = os.path.expanduser(key_file)
try:
key = paramiko.RSAKey.from_private_key_file(privatekey)
except paramiko.PasswordRequiredException:
key = paramiko.RSAKey.from_private_key_file(privatekey,key_file_pwd)
ssh = paramiko.SSHClient()
ssh.load_system_host_keys(filename=filename)
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname=hostname,username=username,pkey=key,port=port)
itchat.send(shutdown_time+u'正在確認裝置是否完成關機操作,大約需要等待60s.', toUserName='filehelper')

等等60秒後確認,因為關機需要一段時間,如果設定太短,可能網路還沒斷開

time.sleep(60)
stdin,stdout,stderr=ssh.exec_command('ping 192.168.1.182 -c 1 | grep 64 | cut -d " " -f 1|head -n 1')
sshConStatus = stdout.read()
sshConStatus =sshConStatus.strip('
')
print type(sshConStatus)
print sshConStatus

如果獲取的值為空,則說明已經關機,否則關機失敗

if sshConStatus != '64':
shutdown_success_err_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
itchat.send(shutdown_success_err_time+u'關機成功', toUserName='filehelper')
else:
shutdown_err_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
itchat.send(shutdown_err_time+u'關機失敗,請連線桌面檢查客戶端程式是否正常執行', toUserName='filehelper')
ssh.close()
itchat.auto_login(hotReload=True,enableCmdQR=2)
itchat.run()
</pre>

python 實現微信遠端控制喚醒內網機器和遠端關閉windows 主機!

客戶端程式碼,寫完扔計劃任務 開機啟動

<pre style="-webkit-tap-highlight-color: transparent; box-sizing: border-box; font-family: Consolas, Menlo, Courier, monospace; font-size: 16px; white-space: pre-wrap; position: relative; line-height: 1.5; color: rgb(153, 153, 153); margin: 1em 0px; padding: 12px 10px; background: rgb(244, 245, 246); border: 1px solid rgb(232, 232, 232); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">import requests
import os
import time
while 1:
time.sleep(30)
r = requests.head("https://awen.me/shutdown")
print r.status_code
if r.status_code == 404:
os.system("shutdown -s -t 5")
</pre>

使用 teamviewer 連線

python 實現微信遠端控制喚醒內網機器和遠端關閉windows 主機!