一直用 FTP 直接登录 UFAX2 网络传真机来获取最新传真,但自从换了新版本的设备后,发现 FTP 被限制了,似乎加了连接授权,再随机分配 FTP 端口。如此一来,只好使用它的客户端。
因为一直以来,都是用 Ajaxplorer(已经改名为 pydio)来管理传真文件,运行在 Ubuntu 主机上,用脚本来自动下载传真。现在只能开一台 Windows 主机,要实现传真自动上传。
实现的步骤:
1. 启用 Windows2003 文件夹安全选项中的审核,监控下载的传真文件,对文件创建成功进行监控。
2. 本地策略中,开启 Object Access 审核选项,不然前一项不生效。
3. 创建自动上传到 Ubuntu 主机的 javascript 脚本程序。
4. 创建 eventtriggers 条目,指定要自动执行的脚本。
开启审核,网上有较多参考文档,如:
http://blogs.splunk.com/2013/07/08/audit-file-access-and-change-in-windows/
开启后,传真文件一旦产生新文件,在管理工具的事件查看器中,我们就可以看到对应的消息,事件ID是 560 (event codes 560 (open object))
创建 eventtriggers 可以查考:
http://www.petri.co.il/how-to-use-eventtriggersexe-to-send-e-mail-based-on-event-ids.htm
http://www.computerperformance.co.uk/Logon/VBScript/eventtriggers.htm
在这个例子中,有段 vbs 代码,下面的 js 是参照它来写的,对于我个人来说,用 js 写代码要清晰简洁很多,如 String.format, Date.format 这两个函数一加,生成字符串又轻松,可读性又好。
代码中用到的类,对应的参考资料:
Win32_NTLogEvent class
http://msdn.microsoft.com/en-us/library/aa394226(v=vs.85).aspx
Converting a Standard Date to a WMI Date-Time Format
http://technet.microsoft.com/en-us/library/ee156558.aspx
其中日期,使用的是 UTC + 时区偏移分钟 的方式来表示,系统当前的时区值,是用 Select * From Win32_TimeZone 来获取的,这样相信各位就能明白函数 getOffsetTime() 具体是什么作用了。
下面是脚本代码,只有几行,很简单。
1. 从系统日志中提取对应的记录
2. 检查事件描述中,是否包含指定文件下的传真 tif 文件
3. 提取 tif 文件名
4. 将 tif 文件上传到服务器
5. 调用服务器上的 shell 脚本对文件作进一步处理(此处未列出,在服务器上,使用 tiff2pdf 工具将 tif 文件转换成 pdf )
6. 删除本地的 tif 文件
注:远程 ssh 操作,使用的是 putty 系统工具,主要是 pscp 上传文件, plink 命令行执行远程 shell 命令。
// use create event trigger command to call this script // eventtriggers /create /eid 560 /tr EventFaxProc /ru administrator /rp password /tk "c:\uploadFax.js" var INTERVAL = -1; var SSH_EXE_PATH = "C:\\Program Files\\PuTTY"; var LOCAL_FAX_PATH = "C:\\Documents and Settings\\Administrator\\My Documents\\我的传真\\收到的传真"; var REMOTE_HOST = "[email protected]"; var REMOTE_PSWD = "mypassword"; var REMOTE_UPLOAD_PATH = "/pydio/faxtemp/tiff"; var REMOTE_CMD = "/pydio/faxtemp/faxconvert.sh"; var WMI_HOST = "."; var DEBUG = false; String.prototype.format = function() { var args = arguments; return this.replace(/\{(\d+)\}/g, function(m, i){ return args[i]; } ); }; Date.prototype.format = function(format) { var date = { "M+": this.getMonth() + 1, "d+": this.getDate(), "h+": this.getHours(), "m+": this.getMinutes(), "s+": this.getSeconds(), "q+": Math.floor((this.getMonth() + 3) / 3), "S+": this.getMilliseconds() }; if (/(y+)/i.test(format)) { format = format.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length)); } for (var k in date) { if (new RegExp("(" + k + ")").test(format)) { format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? date[k] : ("00" + date[k]).substr(("" + date[k]).length)); } } return format; }; var objWMIService; var cmdPara = DEBUG ? "/K" : "/C"; var cmdWin = DEBUG ? 4 : 0; main(); function main() { var pathName = "winmgmts:{impersonationLevel=impersonate}!\\\\{0}\\root\\cimv2".format(WMI_HOST); echo(pathName); objWMIService = GetObject(pathName); var queryString = "Select * from Win32_NTLogEvent" + " Where TimeGenerated>='{0}' and LogFile='Security' and EventIdentifier=560".format(getOffsetTime()); var loggedEvents = objWMIService.ExecQuery(queryString); if (loggedEvents.Count == 0) { echo("events not found."); WScript.Quit(); } var e = new Enumerator(loggedEvents); var pos = 0; for(; !e.atEnd(); e.moveNext()) procFax(e.item(), pos++); echo("Fax upload and convert to pdf completed."); } function echo(msg) { if (DEBUG) WScript.echo(msg); } function getOffsetTime() { var bias = 0; var timeZone = objWMIService.ExecQuery("Select * From Win32_TimeZone"); var e = new Enumerator(timeZone); for(; !e.atEnd(); e.moveNext()) { bias = e.item().Bias; } var currentDate = new Date(); currentDate.setSeconds(currentDate.getSeconds() + INTERVAL); return "{0}.000000{1}".format(currentDate.format("yyyyMMddhhmmss"), bias >= 0 ? ("+" + bias) : bias); } function procFax(event, pos) { var parttern = "Object Name:\\s+{0}\\\\(.*)".format(LOCAL_FAX_PATH.replace(/\\/g, "\\\\")); if (pos == 0) echo(parttern + "\r\n" + event.Message); var regExp = new RegExp(parttern, "i"); var matches = regExp.exec(event.Message); if (matches == null) return; var fileName = matches[1]; echo("{0}\r\n{1}\r\n{2}".format(matches[0], fileName, event.TimeGenerated)); sshUpload(fileName); } function sshUpload(fileName) { var objShell = WScript.CreateObject("WScript.Shell"); var cmd = "cmd.exe {6} \"\"{0}\\pscp.exe\" -pw {1} \"{2}\\{3}\" {4}:{5}\"".format( SSH_EXE_PATH, REMOTE_PSWD, LOCAL_FAX_PATH, fileName, REMOTE_HOST, REMOTE_UPLOAD_PATH, cmdPara); var returnValue = objShell.Run(cmd, cmdWin, true); if (returnValue == 0) { } else { echo("SSH upload failured.\r\n\r\nCommand Line:\r\n{0}\r\n\r\nreturn value:{1}".format(cmd, returnValue)); if (!DEBUG) return; } fileName = fileName.replace(/\.tif/, ""); cmd = "cmd.exe {5} \"\"{0}\\plink.exe\" {1} -pw {2} \"echo -e \"{2}\" | sudo -S {3} {4} \"\"".format( SSH_EXE_PATH, REMOTE_HOST, REMOTE_PSWD, REMOTE_CMD, fileName, cmdPara); var returnValue = objShell.Run(cmd, cmdWin, true); if (returnValue == 0) { objShell.Run("cmd.exe {2} \"Del /Q \"{0}\\{1}.tif\"\"".format(LOCAL_FAX_PATH, fileName, cmdPara), cmdWin, true); } else { echo("SSH command failured.\r\n\r\nCommand Line:\r\n{0}\r\n\r\nreturn value:{1}".format(cmd, returnValue)); return; } }
其它参考资料:
plink 如何执行 sudo
http://www.zimbra.com/forums/installation/10553-solved-sudo-sorry-you-must-have-tty-run-sudo.html