Cygwin/WSL调用Windows schtasks命令操作Windows计划任务系列函数(查询、启用、禁用、删除)

发布时间 2023-10-23 14:19:39作者: CrossPython

新增、删除、查询任务计划

#wintask-query    #根据任务名称关键词查询Windows计划任务
#wintask-del      #根据任务名称关键词删除Windows计划任务,也可以传递计划任务完整路径
#wintask-run      #根据任务名称关键词立即运行Windows计划任务
#wintask-enable   #根据任务名称关键词启用Windows计划任务
#wintask-disable  #根据任务名称关键词禁用Windows计划任务

wintask-query(){
	# 根据任务名称关键词查询Windows计划任务
	# Usage:wintask-query xxx
	#————————————————————————————————————————————————————————————————————————————————————————————————————
	#gsudo schtasks.exe /Query /V /FO LIST|awk 'BEGIN{IGNORECASE = 1;}/TaskName:.*'$1'*/,/^\s+$/{print}'
	#修复正则匹配@20221226:
	#1、精确匹配多个相似任务名:eg:stop-potplayer OR stop-potplayer2
	#2、适配查询参数中带路径分隔符反斜杠的情况(\)
	gsudo schtasks.exe /Query /V /FO LIST|awk 'BEGIN{IGNORECASE = 1;}/TaskName:.*?'"${1//\\/\\\\}"'.*?$/,/^\s+$/{print}' 
}

wintask-del(){
	# 根据任务名称关键词删除Windows计划任务,也可以传递计划任务完整路径
	#  Usage:wintask-del xxx
	#     eg:wintask-del stop-potplayer2      #关键字搜索
	#         wintask-del '\Cygwin自用\定时执行命令:stop-potplayer2'  #任务完整路径
	if [ $# -ge 1 ] && [[ "$1" != "" ]];
	then
		if [[ $1 =~ ^\\ ]];
		then
			local taskName=$1
		else
			#local taskName=$(wintask-query "$1"|dos2unix|awk '/TaskName/{printf $2;exit}')
			local taskNames="$(wintask-query $1|dos2unix|awk '/TaskName/{sub($1" ","");sub(/^[ \t]*/,"");print $0}')"  #适配关键词匹配到多个任务的情况
		fi
		[ -z "${taskNames}" ] && local taskNames=("${taskName//\\/\\\\}")
		#local taskCount=(${taskNames})
		declare -a taskCount
		while read -u 0 taskName
		do
			local taskCount=("${taskCount[@]}" "$taskName")
		done<<<"$taskNames"
		if [ ${#taskCount[*]} -gt 1 ];
		then
			echo -e "警惕操作:\"$1\" 匹配到多个任务!(${#taskCount[*]})"
			#echo "${taskCount[*]}"|sed -r 's/ /\n/g'
			echo "$taskNames"
			read -p "是否继续操作?(y/n,yes/no),默认为no: " delcontinue
			if [[ ! "${delcontinue,,}" == "y" && ! "${delcontinue,,}" == "yes" ]];
			then
				echo "退出操作..." && return
			fi
		elif [ ${#taskCount[*]} -eq 1 ];
		then
			read -p "是否确认要删除任务 ${taskCount[0]}?(y/n,yes/no),默认为no: " delcontinue
			if [[ ! "${delcontinue,,}" == "y" && ! "${delcontinue,,}" == "yes" ]];
			then
				echo "退出操作..." && return
			fi
		fi
		#for taskName in `read -u 0`
		while read -u 0 taskName
		do
			#echo "Do => $taskName"
			gsudo schtasks.exe /Delete /TN "$taskName" /F
		done<<<"${taskNames//\\/\\\\}"
	else
		echo -e "Need Paramter: Task Name KeyWord or Full Path!"
	fi
}

wintask-run(){
	# 根据任务名称关键词立即运行Windows计划任务;
	# Usage:wintask-run xxx
	# 可传递具体任务路径或任务关键字进行搜索;
	# Example:
	# wintask-run '\Cygwin自用\语音整点报时' || wintask-run '\Cygwin自用\定时执行命令:alarm'
	#     OR
	# wintask-run 语音整点报时
	if [ $# -ge 1 ] && [[ "$1" != "" ]];
	then
		if [[ $1 =~ ^\\ ]];
		then
			local taskName=$1
		else
			#local taskName=$(wintask-query $1|dos2unix|awk '/TaskName/{printf $2;exit}')
			local taskNames="$(wintask-query $1|dos2unix|awk '/TaskName/{sub($1" ","");sub(/^[ \t]*/,"");print $0}')" #适配关键词匹配到多个任务的情况
		fi
		[ -z "${taskNames[*]}" ] && local taskNames=("$taskName")
		declare -a taskCount
		while read -u 0 taskName
		do
			local taskCount=("${taskCount[@]}" "$taskName")
		done<<<"$taskNames"
		#local taskCount=(${taskNames[@]})
		if [ ${#taskCount[*]} -gt 1 ];
		then
			echo -e "提示:\"$1\" 匹配到多个任务!(${#taskCount[*]})"
			#echo "${taskCount[*]}"|sed -r 's/ /\n/g'
			echo "$taskNames"|awk '{print NR" ):"$0;}'
			while :;
			do
				read -p "请输入序号选择你要执行的任务(输入 all/a 运行全部任务,q 或 0 退出操作): " taskChoose
				if [ -z "$taskChoose" ] || [[ "${taskChoose,,}" == "q" || "${taskChoose,,}" == "0" ]];then
					echo "退出操作..." && return
				elif expr "$taskChoose" + 0 &>/dev/null;
				then
					local taskName=$(echo "$taskNames"|awk 'NR=='$taskChoose'{print;exit}' 2>/dev/null)
					[ ! -z "$taskName" ] && {
						echo "运行任务:$taskName"
						gsudo schtasks.exe /Run /TN "$taskName"
						return
						} || echo "序号选择无效,请重新选择!"
				elif [[ "${taskChoose,,}" == "all" || "${taskChoose,,}" == "a" ]];
				then
					echo "运行全部任务:" && break
				else
					echo "无效选择,退出操作..." && return
				fi
			done
		fi
		#for taskName in $taskNames
		while read taskName
		do
			#echo "Do => $taskName"
			gsudo schtasks.exe /Run /TN "$taskName"
		done<<<"${taskNames//\\/\\\\}"
	else
		echo -e "Need Paramter: Task Name KeyWord or Full Path!"
	fi
}

wintask-enable(){
	# 根据任务名称关键词启用Windows计划任务
	# Usage:wintask-enable xxx
	if [ $# -ge 1 ] && [[ "$1" != "" ]];
	then
		if [[ $1 =~ ^\\ ]];
		then
			local taskName=$1
		else
			#local taskName=$(wintask-query $1|dos2unix|awk '/TaskName/{printf $2;exit}')
			#local taskNames=$(wintask-query $1|dos2unix|awk '/TaskName/{gsub(/TaskName:[\t| ]+/,"");print}') #兼容计划任务名包含空格的情况
			local taskNames=$(wintask-query $1|dos2unix|awk '/TaskName/{gsub(/TaskName:[\t| ]+/,"");taskname=$0}\
														/Scheduled Task State/{if($NF=="Disabled"){printtaskname="true"}}\
														/Repeat: Stop If Still Running/{if(printtaskname=="true"){\
															print taskname;\
															printtaskname="";\
														}}')  #仅搜索包含关键词且处于禁用状态的任务
		fi
		[ -z "$taskNames" ] && taskNames="$taskName"
		[ -z "$taskNames" ] && echo "“$1” 没有找到任何匹配的任务!" && return
		[ $(echo "$taskNames"|wc -l) -gt 1 ] && {
			echo "$taskNames"
			read -p "“$1” 匹配到多于一个的计划任务,是否批量启用以上任务?"$'\n'"> " goContinue
			[[ ! "${goContinue,,}" == "yes" && ! "${goContinue,,}" == "y" ]] && echo "取消操作..." && return
			}
		OLD_IFS=$IFS
		IFS=$(echo -e "\n")
		#for taskName in $taskNames
		while read taskName
		do
			#echo "操作任务:=> $taskName"
			gsudo schtasks.exe /CHANGE /ENABLE /TN "$taskName"
		done<<<"${taskNames//\\/\\\\}"
		IFS=$OLD_IFS
	else
		echo -e "Need Paramter: Task Name KeyWord or Full Path!"
	fi
}

_wintask-disable-for-select(){
	# 根据任务名称关键词禁用Windows计划任务
	# 此函数专供SSH远程链接会话序号选择使用(因手机上不好输入或者复制计划任务的网址途径)
	if [ $# -ge 1 ] && [[ "$1" != "" ]];
	then
		if [[ $1 =~ ^\\ ]];
		then
			local taskName=$1
		else
			local taskNames=$(wintask-query $1|dos2unix|awk '/TaskName/{gsub(/TaskName:[\t| ]+/,"");print}') #兼容计划任务名包含空格的情况
		fi
		[ -z "$taskNames" ] && taskNames="$taskName"
		echo "$taskNames"|awk '{printf "%2d):%s\n",NR,$0}'
		declare chooseTask
		while [ -z "$chooseTask" ];
		do
			read -p "请输入序号选择你要禁用的计划任务(0/q:退出,p/l:再次打印列表):"$'\n'"> " chooseTask
			[ -z "$chooseTask" ] && echo "退出操作..." && return
			[[ "$chooseTask" == "0" || "${chooseTask,,}" == "q" ]] && echo "退出操作..." && return
			[[ "${chooseTask,,}" == "p" || "${chooseTask,,}" == "l" ]] && {
				echo "$taskNames"|awk '{printf "%2d):%s\n",NR,$0}'
				chooseTask="" && continue
				}
			local taskName=$(echo "$taskNames"|sed -n "${chooseTask}p" 2>/dev/null)
			[ ! -z "$taskName" ] && break || {
				echo "选择无效,请重新选择!"
				chooseTask=""
			}
		done
		#echo "操作任务=>: $taskName"
		SSH_CONNECTION="" wintask-disable "$taskName"
	else
		echo -e "Need Paramter: Task Name KeyWord or Full Path!"
	fi	
}

wintask-disable(){
	# 根据任务名称关键词禁用Windows计划任务
	# Usage:wintask-disable xxx
	declare taskName
	declare taskNames
	if [ $# -ge 1 ] && [[ "$1" != "" ]];
	then
		if [ ! -z "$SSH_CONNECTION" ];then
			print_color 3 "当前通过ssh远程连接,提供序号选择列表:"
			_wintask-disable-for-select "$@"
			return
		fi
		if [[ $1 =~ ^\\ ]];
		then
			local taskName=$1
		else
			#local taskName=$(wintask-query $1|dos2unix|awk '/TaskName/{printf $2;exit}')
			#local taskNames=$(wintask-query $1|dos2unix|awk '/TaskName/{print $2}') #适配关键词匹配到多个任务的情况
			local taskNames=$(wintask-query $1|dos2unix|awk '/TaskName/{gsub(/TaskName:[\t| ]+/,"");print}') #兼容计划任务名包含空格的情况
		fi
		[ -z "$taskNames" ] && taskNames="$taskName"
		[ -z "$taskNames" ] && echo "“$1” 没有找到任何匹配的任务!" && return
		[ $(echo "$taskNames"|wc -l) -gt 1 ] && {
			echo "$taskNames"
			read -p "“$1” 匹配到多于一个的计划任务,是否批量禁用以上任务?"$'\n'"> " goContinue
			[[ ! "${goContinue,,}" == "yes" && ! "${goContinue,,}" == "y" ]] && echo "取消操作..." && return
			}
		OLD_IFS=$IFS
		IFS=$(echo -e "\n")
		#for taskName in $taskNames
		while read taskName
		do
			#echo "操作任务=>: $taskName"
			gsudo schtasks.exe /CHANGE /DISABLE /TN "$taskName"
		done<<<"${taskNames//\\/\\\\}"
		IFS=$OLD_IFS
	else
		echo -e "Need Paramter: Task Name KeyWord or Full Path!"
	fi	
}

  

 

20230223代码有完善更新,最新代码请查阅Gitee源码仓库:

https://gitee.com/hexiyou/shell-scripts/blob/master/wintask-funcs.sh

二次包装函数:

list-schtasks 、 wintasks、findtasks列出查询任务计划:

list-schtasks() {
    ## 在终端列出所有的Windows任务计划;
	OLD_IFS=$IFS
    IFS=$(echo -e "\n")
	local apppath="schtasks"
	local schbakpath='\Cygwin自用\'
	if [ "$(type -t $apppath)" == "file" ];then
		if [ ! -z "$1" ];then #$1可指定要查询的路径,也可以指定显示任务的XML
			if [[ "${1,,}" == "-a" || "${1,,}" == "all" || "${1,,}" == "--all" ]];
			then
				local schbakpath='\'
				echo -e "查询本机所有任务计划..."
			elif [[ "${1,,}" == "--xml" ]];then
				gsudo schtasks /Query /TN "$schbakpath" /XML ONE
				return
			else
				local schbakpath="$1"
			fi
		fi	
		#gsudo schtasks /Query /TN "$schbakpath" /XML ONE
		#TODO:后期使用 xmlstarlet 解析更复杂的XML信息;
		gsudo schtasks /Query /TN "$schbakpath" /XML ONE|awk -F "[><]" '\
			/<URI>/{printf $3"\t";needPrintTime=true};\
			/<Enabled>/{if($3=="false"){printf "\t\033[31m【禁用】\033[0m";}}\
			/* StartBoundary有多个定时器时仅显示第一个 */
			/<StartBoundary>/{printf "\t"$3};\
			/<BootTrigger>/{printf "\t系统启动时"};\
			/<Delay>/{printf "\t延迟"$3};\
			/<Interval>/{printf "\t"$3"@"};\
			/<Duration>/{printf $3};\
			/<DaysInterval>/{printf "\t每天"};\
			/<Command>/{printf "\t||"$3" ";getline;if(match($0,/Arguments/)){printf $3"\n";}else{printf "\n"}};\
		'
	else
		print_color 9 "program not found!\npath:${apppath//\\/\\\\} "
	fi
	IFS=$OLD_IFS
} 

# 此函数转为使用alias调用 findtasks实现更佳,更符合语义,故先注释掉
#findalarm() {
#	#查找已设置的任务闹钟
#	eval list-schtasks|grep alarm
#}

findtasks() {
	## 根据名称或命令行参数查找任务计划
	# --- 默认仅查找启用的任务,可附加参数查找禁用的任务
	# eg:
	# findtasks 录制 --disable
	# findtasks 录制 --enable
	# findtasks 录制 --all  #同时查找禁用和启用的任务
	local name="$1"
	[ -z "$name" ] && print_color 40 "\$1 请传递要查找的关键字!" && return
	shift 1
	#eval list-schtasks|grep "$name"
	eval wintasks "$@"|grep "$name"
}
alias findalarm='findtasks alarm'
alias findrecordlive='findtasks recordlive'
alias findtasksonce='findtasks "||" --once'

  

wintasks:按状态仅列出启用或被禁用的计划任务

 
wintasks() {
	#按状态仅列出启用或被禁用的服务
	#See Also:剔除$@最后一个参数:https://www.igiftidea.com/article/13591115462.html
	if [[ "${@:$#}" == "--disable" ]];then
		#unset ${#_args[@]}-1
		#set -- "$@"
		#set -- "${@:0:$#}"
		set -- "${@:1:$(($#-1))}" # <-- 删除最后一个参数
		list-schtasks "$@"|grep '禁用'
	elif [ $# -eq 0 ] || [[ "${@:$#}" == "--enable" || "${@:$#}" == "--active" ]];then
		[ $# -gt 0 ] && set -- "${@:1:$#-1}"  # 防止参数个数为零时报错:-bash: $#-1: 子串表达式 < 0
		list-schtasks "$@"|grep -v '禁用' # <--- 激活的计划任务
	elif [[ "${@:$#}" == "--all" ]];then  #列出所有状态的任务(包含禁用或启用!)
		[ $# -gt 0 ] && set -- "${@:1:$#-1}"
		list-schtasks "$@"
	elif [[ "${@:$#}" == "--once" ]];then  #列出仅执行一次的任务(排除需要每天执行的任务)
		[ $# -gt 0 ] && set -- "${@:1:$#-1}"
		list-schtasks "$@"|grep -v '每天'
	elif [[ "${@:$#}" == "--disable" ]];then  #仅列出已禁用的任务
		[ $# -gt 0 ] && set -- "${@:1:$#-1}"
		list-schtasks "$@"|grep '禁用'
	else
		list-schtasks "$@"
	fi
}