#!/bin/bash
#如果携带4个参数,$1是附件文件,文件不存在或此处为空,则会只以文本消息发送,反之会发送文本消息和文本文件消息
#$2是应用ID
#$3是用户ID
#$4是文本消息内容
#如果携带3个参数, $1是应用ID
#$2是用户ID
#$3是文本消息内容
if [[ $# -eq 4 ]]; then
_UpLoadFile_="$1"
fi
CropID=''
Secret=''
GURL="https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=$CropID&corpsecret=$Secret"
Gtoken=$(/usr/bin/curl -s -G $GURL | awk -F'"' '{print $10}')
MUPURL="https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=$Gtoken&type=file"
PURL="https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=$Gtoken"
if [[ -f "$_UpLoadFile_" ]]; then
newfilename="$(echo "$(md5sum $_UpLoadFile_ | awk '{print $1}').$(date +%s%N).62e3f7499c2e8aa5af6fe58e0cecdaa3" | md5sum | awk '{print $1}').txt"
/bin/cp -f $_UpLoadFile_ ./$newfilename
media_id="$(curl -s --form "file=@$newfilename" "$MUPURL" 2>/dev/null | egrep -o "\"media_id\":\"[^\"]+\"" | awk -F'"' '{print $4}')"
if [[ -z "$media_id" ]]; then
media_id="$(curl -s --form "file=@$newfilename" "$MUPURL" 2>/dev/null | egrep -o "\"media_id\":\"[^\"]+\"" | awk -F'"' '{print $4}')"
fi
fi
function body_file() {
local int AppID=$1
local UserID="$2"
local MediaID="$3"
local Msg="$(echo "$@" | awk '{$1="";$2="";$3="";printf"%s\n",$0}')"
printf '{'
printf '"touser": '"\"$UserID\""","
printf '"toparty": '"\"\""","
printf '"totag": '"\"\""","
printf '"toall" : 0,'
printf '"msgtype": "file",'
printf '"agentid": '"\"$AppID\""","
printf '"file" : {'
printf '"media_id" : '"\"$MediaID\""
printf '},'
printf '"safe":"0"'
printf '}'
}
function body_text() {
local int AppID=$1
local UserID="$2"
local Msg="$(echo "$@" | awk '{$1="";$2="";printf"%s\n",$0}')"
printf '{'
printf '"touser": '"\"$UserID\""","
printf '"toparty": '"\"$PartyID\""","
printf '"msgtype": "text",'
printf '"agentid": '"\"$AppID\""","
printf '"text": {'
printf '"content": '
echo -e "\"$Msg\""
printf '},'
printf '"safe":"0"'
printf '}'
}
nginx_proxys=(-)
for ((i = 0; i < ${#nginx_proxys[@]}; i++)); do
proxy=${nginx_proxys[$i]}
case $proxy in
-)
if [[ -n "$media_id" ]]; then
http_code=$(curl --connect-timeout 3 --no-keepalive --retry 3 -w '%{http_code}\n' -s -o /dev/null --data-ascii "$(body_text "$2" "$3" "$4\n消息文本附件:\n$newfilename")" $PURL 2>/dev/null)
http_code=$(curl --connect-timeout 3 --no-keepalive --retry 3 -w '%{http_code}\n' -s -o /dev/null --data-ascii "$(body_file "$2" "$3" "$media_id")" $PURL 2>/dev/null)
else
http_code=$(curl --connect-timeout 3 --no-keepalive --retry 3 -w '%{http_code}\n' -s -o /dev/null --data-ascii "$(body_text "$1" "$2" "$3")" $PURL 2>/dev/null)
fi
;;
*)
if [[ -n "$media_id" ]]; then
http_code=$(curl -x $proxy --connect-timeout 3 --no-keepalive --retry 3 -w '%{http_code}\n' -s -o /dev/null --data-ascii "$(body_text "$2" "$3" "$4\n消息文本附件:\n$newfilename")" $PURL 2>/dev/null)
http_code=$(curl -x $proxy --connect-timeout 3 --no-keepalive --retry 3 -w '%{http_code}\n' -s -o /dev/null --data-ascii "$(body_file "$2" "$3" "$media_id")" $PURL 2>/dev/null)
else
http_code=$(curl -x $proxy --connect-timeout 3 --no-keepalive --retry 3 -w '%{http_code}\n' -s -o /dev/null --data-ascii "$(body_text "$1" "$2" "$3")" $PURL 2>/dev/null)
fi
;;
esac
[[ $http_code == 200 ]] && break
done
#!/bin/bash
##############################################################################
# 脚本名称: wechat_work_msg.sh
# 脚本功能: 企业微信消息发送脚本(支持文本消息/文本+文件附件)
# 使用说明:
# 1. 先配置CropID(企业ID)和Secret(应用Secret)
# 2. 两种调用方式:
# - 仅文本消息: ./脚本名 应用ID 用户ID 文本内容
# - 文本+文件: ./脚本名 附件文件 应用ID 用户ID 文本内容
# 依赖工具: curl、awk、md5sum
# 注意事项:
# - 附件文件大小需符合企业微信限制(文件类型≤20MB)
# - 确保服务器能访问企业微信API(https://qyapi.weixin.qq.com)
##############################################################################
# ======================== 配置项(必填!请替换为实际值) ========================
CropID="your_corp_id" # 企业微信企业ID(从企业微信后台获取)
Secret="your_app_secret" # 企业微信应用Secret(从应用管理后台获取)
TEMP_DIR="/tmp/wechat_msg" # 临时文件存储目录
LOG_FILE="/var/log/wechat_msg.log" # 运行日志文件
# ======================== 日志函数 ========================
log() {
local level=$1
local msg=$2
echo "[$(date +'%Y-%m-%d %H:%M:%S')] [$level] $msg" >> ${LOG_FILE}
}
# ======================== 初始化 ========================
# 创建临时目录
mkdir -p ${TEMP_DIR}
chmod 700 ${TEMP_DIR}
# 初始化变量
_UpLoadFile_=""
media_id=""
newfilename=""
http_code=""
errcode=""
# ======================== 参数解析 ========================
# 检查参数数量
if [[ $# -ne 3 && $# -ne 4 ]]; then
log "ERROR" "参数数量错误!用法:"
log "ERROR" " 仅文本: $0 <应用ID> <用户ID> <文本内容>"
log "ERROR" " 文本+文件: $0 <附件文件> <应用ID> <用户ID> <文本内容>"
echo "参数数量错误!"
echo "用法:"
echo " 仅文本: $0 <应用ID> <用户ID> <文本内容>"
echo " 文本+文件: $0 <附件文件> <应用ID> <用户ID> <文本内容>"
exit 1
fi
# 解析参数
if [[ $# -eq 4 ]]; then
_UpLoadFile_="$1"
AppID="$2"
UserID="$3"
MsgContent="$4"
log "INFO" "模式:文本+文件 | 附件文件: $_UpLoadFile_ | 应用ID: $AppID | 用户ID: $UserID"
elif [[ $# -eq 3 ]]; then
AppID="$1"
UserID="$2"
MsgContent="$3"
log "INFO" "模式:仅文本 | 应用ID: $AppID | 用户ID: $UserID"
fi
# ======================== 获取企业微信Access Token ========================
GURL="https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${CropID}&corpsecret=${Secret}"
log "INFO" "获取Token请求URL: ${GURL}"
# 调用API获取token
token_response=$(/usr/bin/curl -s --connect-timeout 5 --retry 2 ${GURL})
Gtoken=$(echo ${token_response} | awk -F'"' '{print $10}')
# 校验token是否获取成功
if [[ -z ${Gtoken} || ${Gtoken} == "null" ]]; then
log "ERROR" "获取Token失败!响应内容: ${token_response}"
echo "获取企业微信Token失败!"
exit 1
fi
log "INFO" "获取Token成功: ${Gtoken:0:10}..." # 仅打印前10位,避免泄露
# ======================== 上传附件文件(如有) ========================
MUPURL="https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=${Gtoken}&type=file"
if [[ -f "${_UpLoadFile_}" && -r "${_UpLoadFile_}" ]]; then
log "INFO" "开始上传附件文件: ${_UpLoadFile_}"
# 生成唯一临时文件名(避免冲突)
newfilename="${TEMP_DIR}/$(echo "$(md5sum ${_UpLoadFile_} | awk '{print $1}').$(date +%s%N)" | md5sum | awk '{print $1}').txt"
# 复制文件到临时目录
/bin/cp -f ${_UpLoadFile_} ${newfilename}
if [[ $? -ne 0 ]]; then
log "ERROR" "复制附件文件失败: ${_UpLoadFile_} -> ${newfilename}"
echo "复制附件文件失败!"
exit 1
fi
# 上传文件到企业微信
upload_response=$(curl -s --connect-timeout 10 --retry 2 --form "file=@${newfilename}" "${MUPURL}")
media_id=$(echo ${upload_response} | egrep -o "\"media_id\":\"[^\"]+\"" | awk -F'"' '{print $4}')
# 第一次上传失败,重试一次
if [[ -z ${media_id} ]]; then
log "WARN" "第一次上传文件失败,重试!响应: ${upload_response}"
sleep 1
upload_response=$(curl -s --connect-timeout 10 --retry 2 --form "file=@${newfilename}" "${MUPURL}")
media_id=$(echo ${upload_response} | egrep -o "\"media_id\":\"[^\"]+\"" | awk -F'"' '{print $4}')
fi
# 校验上传结果
if [[ -z ${media_id} ]]; then
log "ERROR" "文件上传失败!响应内容: ${upload_response}"
echo "附件文件上传失败!"
# 清理临时文件
rm -f ${newfilename}
exit 1
fi
log "INFO" "文件上传成功,media_id: ${media_id:0:10}..."
else
if [[ -n "${_UpLoadFile_}" ]]; then
log "WARN" "附件文件不存在或不可读: ${_UpLoadFile_},将仅发送文本消息"
echo "附件文件不存在或不可读,将仅发送文本消息!"
fi
fi
# ======================== 构造消息JSON函数 ========================
# 构造文件消息JSON
body_file() {
local AppID=$1
local UserID=$2
local MediaID=$3
cat << EOF
{
"touser": "${UserID}",
"toparty": "",
"totag": "",
"msgtype": "file",
"agentid": "${AppID}",
"file": {
"media_id": "${MediaID}"
},
"safe": "0"
}
EOF
}
# 构造文本消息JSON
body_text() {
local AppID=$1
local UserID=$2
local Msg=$3
# 转义JSON特殊字符(\、"、换行)
Msg=$(echo "${Msg}" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/\n/\\n/g')
cat << EOF
{
"touser": "${UserID}",
"toparty": "",
"totag": "",
"msgtype": "text",
"agentid": "${AppID}",
"text": {
"content": "${Msg}"
},
"safe": "0"
}
EOF
}
# ======================== 发送消息 ========================
PURL="https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=${Gtoken}"
log "INFO" "消息发送URL: ${PURL}"
# 代理配置(如需使用代理,修改此处)
nginx_proxys=(-)
# 遍历代理发送消息
for proxy in "${nginx_proxys[@]}"; do
# 构建curl参数(是否使用代理)
curl_proxy=""
if [[ ${proxy} != "-" ]]; then
curl_proxy="-x ${proxy}"
log "INFO" "使用代理: ${proxy}"
fi
# 发送消息逻辑
if [[ -n "${media_id}" ]]; then
# 1. 发送文本消息(包含附件说明)
text_msg="${MsgContent}\n消息文本附件:\n$(basename ${_UpLoadFile_})"
text_json=$(body_text "${AppID}" "${UserID}" "${text_msg}")
log "INFO" "发送文本消息JSON: ${text_json:0:100}..."
send_response=$(curl ${curl_proxy} --connect-timeout 5 --no-keepalive --retry 3 -w 'HTTP_CODE:%{http_code}\n' -s -o - --data-ascii "${text_json}" ${PURL})
http_code=$(echo ${send_response} | grep -o "HTTP_CODE:[0-9]*" | awk -F':' '{print $2}')
errcode=$(echo ${send_response} | egrep -o "\"errcode\":[0-9]+" | awk -F':' '{print $2}')
log "INFO" "文本消息发送响应:HTTP_CODE=${http_code}, errcode=${errcode}"
# 2. 发送文件消息
file_json=$(body_file "${AppID}" "${UserID}" "${media_id}")
log "INFO" "发送文件消息JSON: ${file_json:0:100}..."
send_response=$(curl ${curl_proxy} --connect-timeout 5 --no-keepalive --retry 3 -w 'HTTP_CODE:%{http_code}\n' -s -o - --data-ascii "${file_json}" ${PURL})
http_code=$(echo ${send_response} | grep -o "HTTP_CODE:[0-9]*" | awk -F':' '{print $2}')
errcode=$(echo ${send_response} | egrep -o "\"errcode\":[0-9]+" | awk -F':' '{print $2}')
log "INFO" "文件消息发送响应:HTTP_CODE=${http_code}, errcode=${errcode}"
else
# 仅发送文本消息
text_json=$(body_text "${AppID}" "${UserID}" "${MsgContent}")
log "INFO" "发送文本消息JSON: ${text_json:0:100}..."
send_response=$(curl ${curl_proxy} --connect-timeout 5 --no-keepalive --retry 3 -w 'HTTP_CODE:%{http_code}\n' -s -o - --data-ascii "${text_json}" ${PURL})
http_code=$(echo ${send_response} | grep -o "HTTP_CODE:[0-9]*" | awk -F':' '{print $2}')
errcode=$(echo ${send_response} | egrep -o "\"errcode\":[0-9]+" | awk -F':' '{print $2}')
log "INFO" "文本消息发送响应:HTTP_CODE=${http_code}, errcode=${errcode}"
fi
# 校验发送结果(errcode=0表示成功)
if [[ ${http_code} == 200 && ${errcode} == 0 ]]; then
log "INFO" "消息发送成功!"
echo "消息发送成功!"
break
else
log "WARN" "消息发送失败,尝试下一个代理(HTTP_CODE=${http_code}, errcode=${errcode})"
fi
done
# ======================== 清理临时文件 ========================
if [[ -f "${newfilename}" ]]; then
rm -f "${newfilename}"
log "INFO" "清理临时文件: ${newfilename}"
fi
# ======================== 最终结果校验 ========================
if [[ ${http_code} != 200 || ${errcode} != 0 ]]; then
log "ERROR" "消息发送最终失败!HTTP_CODE=${http_code}, errcode=${errcode}"
echo "消息发送失败!"
exit 1
fi
exit 0
Categories:
系统运维