使用powershell工具取代ftp.exe工具

在使用Jenkins通过Windowsftp.exe进行持续发布的工作时受到很多限制:

  • 不支持被动模式(PASV),参考链接stackoverflow
    1. 使用此工具时,客户端必须开放防火墙供服务端“回访”。
    2. 当客户机处于NAT网络时,主动回访可能会被路由阻塞。
  • 健壮性差,error pass silently
    1. 脚本只能按顺序执行
    2. 出错后无法停止
    3. 出现异常时无法针对异常调整流程
    4. 执行结束时返回值总是0,上传过程出现异常只能通过日志发现,无法显式被jenkins捕获。

可替代方案中:

  • Putty提供的psftp工具无法正常连接。
  • Winscp提供的sftp工具虽然可以提供被动模式,但是自动化执行的方式与ftp.exe类似:逐行执行文件中的ftp命令,参考链接
  • MS Web Deploy无法定制上传的内容。

偶然间发现了powershell下通过.NET框架库实现的PSFTP包,可以兼顾解决上述两个问题。

准备工作

  1. 调整powershell脚本的执行策略,Set-ExecutionPolicy

  2. 下载PowerShell FTP Client Module。单用户使用请解压至%USERPROFILE%\Documents\WindowsPowerShell\Modules,全局路径在%WINDIR%\System32\WindowsPowerShell\v1.0\Modules

在powershell中执行

1
Import-Module PSFTP

无异常则说明导入成功。

脚本概述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 构建凭据对象
$user = "shine"
$Password = ConvertTo-SecureString -String password -AsPlainText -Force
$credential = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $user,$password
# 导入PSFTP包
Import-Module PSFTP
# 初始化FTP链接
Set-FTPConnection -Credentials $credential -Server ftp://10.20.30.40 -Session ftpSession -UsePassive
# 检查路径/path/to/bin/是否存在
try {
$bin = Get-FTPChildItem -Session ftpSession -Path /path/to/bin/ -Recurse -Depth 2
}
catch {
# 目标路径不存在,创建空目录
Write-Output "Path /path/to/bin/ not exist,Try to build a new one ..."
New-FTPItem -Session ftpSession -Name bin -Path /ac_user_api/
}
# 删除目标路径下的文件
if(![String]::IsNullOrEmpty($bin)){
Write-Output "Cleaning up /path/to/bin/ ..."
Remove-FTPItem -Session ftpSession -Path /path/to/bin/ -Recurse
New-FTPItem -Session ftpSession -Name bin -Path /ac_user_api/
}
else{
Write-Output "Folder /path/to/bin/ is Empty, skip clean up step."
}
# 遍历当前目录的文件,若为dll文件则上传至/path/to/bin/
cd bin
Get-ChildItem . | ForEach-Object -Process{
if($_ -is [System.IO.FileInfo] -and $_.ToString().EndsWith(".dll"))
{
Send-FTPItem -Session ftpSession -Path /path/to/bin/ -LocalPath $_.name -Overwrite
}
}
Write-Output "Upload Success!"
# 执行完毕,显式退出
exit 0