1、在编写命令行执行的Python文件时出现:ValueError: mutually exclusive arguments must be optional
不要采用这种写法:
group=parser.add_mutually_exclusive_group(required=True)
group.add_argument('--md5',help='specifies MD5 algorithm',action='store_true',default=True)
按照这样来写(建议required都为False,在后续自写判断可以避免执行其他查询操作造成的报错!):
parser=argparse.ArgumentParser("python file system hashing ..filehash")
parser.add_argument('-v','-verbose',help='allows progress messages to be displayed',action='store_true')
parser.add_argument('--md5',help='specifies MD5 algorithm',action='store_false')
parser.add_argument('--sha512', help='specifies SHA512 algorithm', action='store_true',default=False)
parser.add_argument('--sha256', help='specifies SHA256 algorithm', action='store_true',default=False)
#可以在-d简称后跟文件路径,也可以在--reportPath全程后跟文件路径
parser.add_argument('-d', '--rootPath', required=True,type=ValidateDirectoryRead,help='specify the root path for hashing')
parser.add_argument('-r', '--reportPath',required=False, type=ValidateDirectoryWrite, help='specify the path for reports and logs will be written')
gl_args=parser.parse_args()
print(gl_args)
'-v','-verbose'前面一个是简称,后面的是全称
default为在输入为空时的默认值
required设置这个参数是否必须输入
type可以跟一个函数或者限定的字符类型(int)用于对输入参数进行判断限制
action跟一个参数,当action=‘store_true’时,默认为FALSE;当action='store_flase'时,默认为TRUE
通过gl_args=parser.parse_args()来获取参数
2、对parser.parse_args()参数进行更新操作,gl_args=parser.parse_args(args=['--rootPath','E:\\Temp\\']),下面是可以对参数进行更新的完整代码。
import argparse
import os,sys
def ValidateDirectoryRead(FileDir):
"""
读取文件路径判断
:param FileDir:
:return:
"""
print("*********")
if not os.path.isdir(FileDir):
raise argparse.ArgumentError("Directory does not exist")
if os.access(FileDir,os.R_OK):
return FileDir
else:
raise argparse.ArgumentError("Directory is not readable")
def ValidateDirectoryWrite(FileDir):
"""
写入文件路径判断
:param FileDir:
:return:
"""
if not os.path.isdir(FileDir):
raise argparse.ArgumentError("Directory does not exist")
if os.access(FileDir, os.W_OK):
return FileDir
else:
raise argparse.ArgumentError("Directory is not writeable")
parser = argparse.ArgumentParser("python file system hashing ..filehash")
parser.add_argument('-v', '--verbose', action='store_true', help='FileHash Version!')
# 指定在--md5后跟一个输入
parser.add_argument('--md5', help='specifies MD5 algorithm', action='store_false')
parser.add_argument('--sha512', help='specifies SHA512 algorithm', action='store_true', default=False)
parser.add_argument('--sha256', help='specifies SHA256 algorithm', action='store_true', default=False)
# 可以在-d简称后跟文件路径,也可以在--reportPath全程后跟文件路径
parser.add_argument('-d', '--rootPath', required=False, type=ValidateDirectoryRead,
help='specify the root path for hashing')
parser.add_argument('-r', '--reportPath', required=False, type=ValidateDirectoryWrite,
help='specify the path for reports and logs will be written')
gl_args = parser.parse_args()
if gl_args.verbose: # 如果只是查询版本信息则返回版本信息化直接退出
print("FileHash Version 1.0")
sys.exit()
if gl_args.rootPath == None:
print("Please enter the path of the file to be processed!")
sys.exit()
if gl_args.reportPath == None: # 如果没有输出目录则获取当前目录并创建输出目录到HashOut
path = os.getcwd()
try:
os.makedirs(path + "\\HashOut\\")
except:
pass
# 更具获取的当前文件执行路径对reportPath默认参数进行更新
tmprootPath = gl_args.rootPath
gl_args = parser.parse_args(args=['--reportPath', path + "\\HashOut\\", '--rootPath', tmprootPath])
print(gl_args)
print(os.listdir(gl_args.rootPath))
if gl_args.md5:
gl_hashType = "MD5"
elif gl_args.sha256:
gl_hashType = "SHA256"
elif gl_args.sha512:
gl_hashType = "SHA512"
else:
gl_hashType = "Unknown"
# logging.error("Unknown Hash Type Specified")
sys.exit()
3、通过argparse可以实现通过命令行进行参数输入,以便于无界面执行,下面附上在Python3下可执行的完整代码,文件hash取证,文件的创建及修改信息等,保护两个.py文件,放在同一个文件夹下,cmd下运行FileHashRun.py即可,python FileHashRun.py -h查看帮助命令。
FileHashRun.py
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# @Time : 2020/9/15 18:51
# @Author : singweek
# @File : FileHashRun.py
import logging
import time
import sys
import FileHash
if __name__=='__main__':
logging.basicConfig(filename="FileHashLog.log",level=logging.DEBUG,format='%(asctime)s %(message)s')
FileHash.ParseCommandLine()
startTime=time.time()
logging.info('System:'+sys.platform)
logging.info('Version:'+sys.version)
"""主要工作函数"""
filesProcessed=FileHash.WalkPath()
endTime=time.time()
duration=endTime-startTime
logging.info("Files Processed:"+str(filesProcessed))
logging.info("Elapsed Time:"+str(duration)+'seconds')
logging.info('')
logging.info("Program Terminated Normally")
logging.info('')
FileHash.DisplayMessage("Program End")
FileHash.py
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# @Time : 2020/9/15 18:54
# @Author : singweek
# @File : FileHash.py
import os
import stat
import time
import hashlib
import csv
import argparse
import logging
import sys
#日志文件导入
log=logging.getLogger('main.FileHashRun')
def ParseCommandLine():
"""
命令行基本参数输入设置,可以在此基础上根据自己的需要设置输入不同的参数
:return:
"""
parser=argparse.ArgumentParser("python file system hashing ..filehash")
parser.add_argument('-v','--verbose', action='store_true',help='FileHash Version!')
# 指定在--md5后跟一个输入
parser.add_argument('-md5','--md5', help='specifies MD5 algorithm', action='store_false')
parser.add_argument('-sha512','--sha512', help='specifies SHA512 algorithm', action='store_true', default=False)
parser.add_argument('-sha256','--sha256', help='specifies SHA256 algorithm', action='store_true', default=False)
# 可以在-d简称后跟文件路径,也可以在--reportPath全程后跟文件路径
parser.add_argument('-d', '--rootPath',required=False,type=ValidateDirectoryRead,help='specify the root path for hashing')
parser.add_argument('-r', '--reportPath',required=False,type=ValidateDirectoryWrite,help='specify the path for reports and logs will be written')
global gl_args
global gl_hashType
gl_args=parser.parse_args()
if gl_args.verbose:#如果只是查询版本信息则返回版本信息化直接退出
print("FileHash Version 1.0")
sys.exit()
if gl_args.rootPath==None:
print("Please enter the path of the file to be processed!")
sys.exit()
if gl_args.reportPath==None:#如果没有输出目录则获取当前目录并创建输出目录到HashOut
path = os.getcwd()
try:
os.makedirs(path + "\\HashOut\\")
except:
pass
#更具获取的当前文件执行路径对reportPath默认参数进行更新
tmprootPath=gl_args.rootPath
gl_args = parser.parse_args(args=['--reportPath', path + "\\HashOut\\",'--rootPath',tmprootPath])
if gl_args.md5:
gl_hashType="MD5"
elif gl_args.sha256:
gl_hashType="SHA256"
elif gl_args.sha512:
gl_hashType="SHA512"
else:
gl_hashType="Unknown"
logging.error("Unknown Hash Type Specified")
sys.exit()
DisplayMessage("Command line processed: Successfully")
return
class CSVWrite:
"""
利用CSV对获取到的取证数据进行存储
"""
def __init__(self,FileName,hashType):
try:
self.csvFile=open(FileName,'w')
self.write=csv.writer(self.csvFile,delimiter=',',quoting=csv.QUOTE_ALL)
self.write.writerow(('File','Path','Size','Modified Time','Access Time','Created Time',hashType,'Owner','Group','Mode'))
except:
log.error("CSV File Failure")
def WriteRow(self,filename,filepath,filesize,mtime,atime,ctime,hashwal,own,grp,mod):
self.write.writerow((filename,filepath,filesize,mtime,atime,ctime,hashwal,own,grp,mod))
def WriteClose(self):
self.csvFile.close()
def ValidateDirectoryRead(FileDir):
"""
读取文件路径判断
:param FileDir:
:return:
"""
if not os.path.isdir(FileDir):
raise argparse.ArgumentError("Directory does not exist")
if os.access(FileDir,os.R_OK):
return FileDir
else:
raise argparse.ArgumentError("Directory is not readable")
def ValidateDirectoryWrite(FileDir):
"""
写入文件路径判断
:param FileDir:
:return:
"""
if not os.path.isdir(FileDir):
raise argparse.ArgumentError("Directory does not exist")
if os.access(FileDir, os.W_OK):
return FileDir
else:
raise argparse.ArgumentError("Directory is not writeable")
def DisplayMessage(msg):
"""
信息输出显示
:param msg:
:return:
"""
print(msg)
def HashFile(File,simpleName,csvwrite):
"""
对单个文件进行hash校验并,默认选择MD5
:param File:
:param simpleName:
:param result:
:return:
"""
#判断路径是否存在,在判断路径不是能是链接,最后判断路径是正确的文件路径
if os.path.exists(File) and not os.path.islink(File) and os.path.isfile(File):
try:#学习到了try后面还可以跟else之前没有用到的
f=open(File,'rb')
except IOError:
log.warning("Open Failed:" + File)
return
else:
try:
rd=f.read()
except IOError:
f.close()
log.warning("Read Failed:"+ File)
return
else:
theFileStats=os.stat(File)
(mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime)=os.stat(File)
DisplayMessage("Processing File:"+File)#打印进程文件名
fileSize=str(size)
#时间格式转换
modifiedTime=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(mtime))
accessTime=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(atime))
createdTime=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(ctime))
ownerID=str(uid)
groupID=str(gid)
fileMode=bin(mode)
"""根据读取的rb文件进行hash值计算获取"""
if gl_args.sha256:
hash=hashlib.sha256()
hash.update(rd)
hexhash=hash.hexdigest()
hashValue=hexhash.upper()
elif gl_args.sha512:
hash=hashlib.sha512()
hash.update(rd)
hexhash=hash.hexdigest()
hashValue=hexhash.upper()
else:#默认选择
hash = hashlib.md5()
hash.update(rd)
hexhash = hash.hexdigest()
hashValue = hexhash.upper()
# print(simpleName,File,fileSize,modifiedTime,accessTime,createdTime,hashValue,ownerID,groupID,mode)
csvwrite.WriteRow(simpleName,File,fileSize,modifiedTime,accessTime,createdTime,hashValue,ownerID,groupID,mode)
return True
else:
log.warning("[%s]"%repr(simpleName), ",FilePath Wrong, Please Check Path!")
return False
def WalkPath():
"""
对需要取证校验的文件进行读取,并将结果写入文件,返回执行成功和错误文件数
:return:
"""
processCount=0
errorCount=0
oCSV=CSVWrite(gl_args.reportPath+'fileSystemReport.csv',gl_hashType)#调用CSV存储函数
log.info('Root Path:'+gl_args.rootPath)
for root,dirs,files in os.walk(gl_args.rootPath):
for file in files:
fname=os.path.join(root,file)
result=HashFile(fname,file,oCSV)
if result is True:
processCount+=1
else:
errorCount+=1
oCSV.WriteClose()
return (processCount,errorCount)
4、getopt参数输入
import sys,getopt
def Get_Input(argv):
"""参数输入"""
try:
opts= getopt.getopt(argv,"srh",['input',"out",'help'])
print(opts)
except getopt.GetoptError:
print('test.py -h 帮助')
sys.exit(2)
opt=opts[0][0][0]
if opt in ("-s"):
starts = opt
print("启动参数", starts)
return starts
elif opt in ("-r"):
runs = opt
print("运行参数",runs)
return runs
else:
print('test.py -s启动浏览器')
print('test.py -r操作浏览器')
sys.exit(2)
inputstring=Get_Input(sys.argv[1:])#输入一个参数