Python自动化工具
用来执行命令并进行交互,比如需要输入账号密码或者确认的场景
linux平台可以用pexpect,但是windows平台有一些差异,比较好用的是pexpect的变种wexpect,如果脚本中用了wexpect,并且要打包成onefile,可以
参考github首先打包wexpect
1.进入wexpect目录执行
pyinstaller main.py -n wexpect
会生成dist文件夹
2.python代码A.py中使用wexpect,注意wexpect.spawn前后必须按照下面添加代码
python
import sys,os,wexpect
#spawn前
real_executable = sys.executable
try:
if sys._MEIPASS is not None:
sys.executable = os.path.join(sys._MEIPASS, "wexpect", "wexpect.exe")
except AttributeError:
pass
child = wexpect.spawn('ssh root@192.168.47.128')
sys.executable = real_executable
#spawn后
try:
child.expect('password',timeout=1)
child.sendline("root@123")
child.expect('#',timeout=1)
child.sendline("touch wexpect")
child.sendline("exit")
except Exception as e:
print("timeout")
print('1.before = ',child.before)
print('2.after = ',child.after)
child.wait()
3.打包成onefile
pyinstaller --onefile --add-data "wexpect路径\dist;." A.py
Windows伪控制台
很少用到,只能参考windows官方文档自己写,启动伪控制台,并且通过管道直接和伪控制台交互,非常方便,传送门
自己随便写的demo如下:
cpp
// PseudoConsoleDemo.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <thread>
#include <string>
#include <codecvt>
#include <memory>
using namespace std;
void Log(string info)
{
//string cmd = "echo " + info;
printf(info.c_str());
}
std::string UTF8ToLocale(const std::string& utf8Str)
{
//Convert utf8 to Unicode
std::wstring_convert<std::codecvt_utf8<wchar_t> > conv;
std::wstring tmpWstr = conv.from_bytes(utf8Str);
//Conver widestr to system code page
int len = WideCharToMultiByte(CP_ACP, NULL, tmpWstr.c_str(), -1, NULL, NULL, NULL, NULL);
char *str = new char[len];
WideCharToMultiByte(CP_ACP, NULL, tmpWstr.c_str(), -1, str, len, NULL, NULL);
return str;
}
HRESULT PrepareStartupInformation(HPCON hpc, STARTUPINFOEXW* psi)
{
// Prepare Startup Information structure
STARTUPINFOEXW si;
ZeroMemory(&si, sizeof(si));
si.StartupInfo.cb = sizeof(STARTUPINFOEX);
// Discover the size required for the list
SIZE_T bytesRequired;
InitializeProcThreadAttributeList(NULL, 1, 0, &bytesRequired);
// Allocate memory to represent the list
si.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, bytesRequired);
if (!si.lpAttributeList)
{
return E_OUTOFMEMORY;
}
// Initialize the list memory location
if (!InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &bytesRequired))
{
HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
return HRESULT_FROM_WIN32(GetLastError());
}
// Set the pseudoconsole information into the list
if (!UpdateProcThreadAttribute(si.lpAttributeList,
0,
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
hpc,
sizeof(hpc),
NULL,
NULL))
{
HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
return HRESULT_FROM_WIN32(GetLastError());
}
*psi = si;
return S_OK;
}
bool WritePipe(HANDLE pipeHd, const char DataBuffer[])
{
DWORD dwBytesToWrite = (DWORD)strlen(DataBuffer);
DWORD dwBytesWritten = 0;
BOOL bErrorFlag = FALSE;
bErrorFlag = WriteFile(
pipeHd, // open file handle
DataBuffer, // start of data to write
dwBytesToWrite, // number of bytes to write
&dwBytesWritten, // number of bytes that were written
NULL);
return bErrorFlag;
}
bool ReadPipe(HANDLE pipeHd)
{
const int BUFFERSIZE = 4096;
char ReadBuffer[BUFFERSIZE] = { 0 };
if (pipeHd == INVALID_HANDLE_VALUE)
{
//printf(("Terminal failure: unable to open file \"\" for read.\n"));
return false;
}
// Read one character less than the buffer size to save room for
// the terminating NULL character.
DWORD dwBytesRead;
DWORD dwBytesToRead = BUFFERSIZE - 1;
if (FALSE == ReadFile(pipeHd, ReadBuffer, dwBytesToRead, &dwBytesRead, NULL))
{
//printf("Terminal failure: Unable to read from file.\n GetLastError=%08x\n", GetLastError());
return false;
}
// This is the section of code that assumes the file is ANSI text.
// Modify this block for other data types if needed.
if (dwBytesRead > 0 && dwBytesRead <= dwBytesToRead)
{
ReadBuffer[dwBytesRead] = '\0'; // NULL character
//printf(("Data read from (%d bytes): \n"), dwBytesRead);
//PseudoConsole use utf8 encode
Log(UTF8ToLocale(ReadBuffer));
return true;
}
else if (dwBytesRead == 0)
{
//printf(("No data read from file\n"));
}
else
{
//printf("\n ** Unexpected value for dwBytesRead ** \n");
}
return false;
}
PWSTR String2PWSTR(const string& str)
{
PWSTR pwstr;
int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.size(), NULL, 0);
pwstr = new WCHAR[len + 1];
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.size(), pwstr, len);
pwstr[len] = '\0';
return pwstr;
}
HPCON SetUpPseudoConsole(std::string cmd, HANDLE& read, HANDLE& write, PROCESS_INFORMATION& proc)
{
COORD size = { 1000, 500 };
HRESULT hr = S_OK;
// Create communication channels
// - Close these after CreateProcess of child application with pseudoconsole object.
HANDLE inputReadSide, outputWriteSide;
// - Hold onto these and use them for communication with the child through the pseudoconsole.
HANDLE outputReadSide, inputWriteSide;
if (!CreatePipe(&inputReadSide, &inputWriteSide, NULL, 0))
{
return NULL;
}
if (!CreatePipe(&outputReadSide, &outputWriteSide, NULL, 0))
{
return NULL;
}
HPCON hPC;
hr = CreatePseudoConsole(size, inputReadSide, outputWriteSide, 0, &hPC);
if (FAILED(hr))
{
return NULL;
}
STARTUPINFOEXW siEx;
PrepareStartupInformation(hPC, &siEx);
// Create mutable text string for CreateProcessW command line string.
const string cmdStr = "C:\\windows\\system32\\cmd.exe /k \"echo off\"";
PCWSTR childApplication = String2PWSTR(cmdStr);
//PCWSTR childApplication = L"C:\\windows\\system32\\cmd.exe /k \"net use \\\\192.168.47.128\"";
// Create mutable text string for CreateProcessW command line string.
const size_t charsRequired = wcslen(childApplication) + 1; // +1 null terminator
PWSTR cmdLineMutable = (PWSTR)HeapAlloc(GetProcessHeap(), 0, sizeof(wchar_t) * charsRequired);
if (!cmdLineMutable)
{
return NULL;
}
wcscpy_s(cmdLineMutable, charsRequired, childApplication);
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
// Call CreateProcess
if (!CreateProcessW(NULL,
cmdLineMutable,
NULL,
NULL,
FALSE,
EXTENDED_STARTUPINFO_PRESENT,
NULL,
NULL,
&siEx.StartupInfo,
&pi))
{
HeapFree(GetProcessHeap(), 0, cmdLineMutable);
return NULL;
}
CloseHandle(inputReadSide);
CloseHandle(outputWriteSide);
//if (!WritePipe(inputWriteSide, "net use \\\\192.168.47.128\r")) {
// printf("write error");
//}
read = outputReadSide;
write = inputWriteSide;
proc = pi;
return hPC;
}
int main()
{
auto t = std::thread([]() {
HANDLE read, write;
PROCESS_INFORMATION pi;
HPCON hpc = SetUpPseudoConsole("net use \\\\192.168.47.128", read, write, pi);
DWORD exitCode;
if (GetExitCodeProcess(pi.hProcess, &exitCode)) {
//printf("get exit code success ,code=%d", exitCode);
STILL_ACTIVE;
if (exitCode == STILL_ACTIVE) {
//printf("process alive");
}
}
else {
Log("get exit code failed");
}
if (!ReadPipe(read)) {
Log("read error");
}
if (!WritePipe(write, "net use \\\\192.168.47.128\r")) {
Log("write error");
}
if (!ReadPipe(read)) {
Log("read error");
}
if (!WritePipe(write, "smbshare\r")) {
Log("write error");
}
if (!ReadPipe(read)) {
Log("read error");
}
if (!WritePipe(write, "smbshare\r")) {
Log("write error");
}
if (!ReadPipe(read)) {
Log("read error");
}
Sleep(100);
if (GetExitCodeProcess(pi.hProcess, &exitCode)) {
Log("get exit code success ,code=" + exitCode);
STILL_ACTIVE;
if (exitCode == STILL_ACTIVE) {
Log("process alive");
}
}
WaitForSingleObject(pi.hProcess, 0);
WaitForSingleObject(pi.hThread, 0);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
ClosePseudoConsole(hpc);
//TerminateProcess
});
t.join();
}