# Robust FTP upload: per-file connection, size-check skip, retry $ErrorActionPreference = "Continue" [System.Net.ServicePointManager]::DefaultConnectionLimit = 64 $FtpHost="116.198.221.125"; $FtpPort=21; $FtpUser="wenchuanyi"; $FtpPass="r7P^f*v7rFts" $RemoteRoot="/wwwroot" $Stage = Join-Path $env:TEMP "wcy_publish_staging" $Log = "D:\CodeBuddy\Pros\WenChuanyi\deploy\ftp_upload.log" $fail = $false function L([string]$m){ Add-Content -Path $Log -Value $m -Encoding UTF8 } function New-FtpReq([string]$path,[string]$method,[int]$timeoutMs=120000){ $uri="ftp://${FtpHost}:${FtpPort}/"+$path.TrimStart('/') $r=[System.Net.FtpWebRequest]::Create($uri) $r.Method=$method $r.Credentials=New-Object System.Net.NetworkCredential($FtpUser,$FtpPass) $r.UsePassive=$true; $r.UseBinary=$true; $r.KeepAlive=$false $r.Timeout=$timeoutMs return $r } function Get-FtpSize([string]$p){ $r=New-FtpReq $p ([System.Net.WebRequestMethods+Ftp]::GetFileSize) 30000 try{ $resp=$r.GetResponse(); $s=$resp.ContentLength; $resp.Close(); return $s }catch{ return -1 } } function UpFile([string]$lp,[string]$rp){ $localSize=(Get-Item $lp).Length $remoteSize=Get-FtpSize $rp if($remoteSize -eq $localSize){ L "SKIP $rp (size ok)"; return $true } for($i=1;$i -le 3;$i++){ try{ $r=New-FtpReq $rp ([System.Net.WebRequestMethods+Ftp]::UploadFile) 240000 $b=[System.IO.File]::ReadAllBytes($lp) $r.ContentLength=$b.Length $s=$r.GetRequestStream() try{ $s.Write($b,0,$b.Length) } finally { $s.Close() } $resp=$r.GetResponse() try{ $resp.Close() }catch{} $after=Get-FtpSize $rp if($after -eq $localSize){ L "UP $rp"; return $true } else{ L "VERIFYFAIL $rp (got $after want $localSize)"; continue } }catch{ L "RETRY($i) $rp : $($_.Exception.Message)" Start-Sleep -Seconds 3 } } L "FAIL $rp" $script:fail=$true return $false } function UpDir([string]$ld,[string]$rd){ foreach($d in Get-ChildItem $ld -Directory){ $c="$rd/$($d.Name)" $mr=New-FtpReq $c ([System.Net.WebRequestMethods+Ftp]::MakeDirectory) 30000 try{ $null=$mr.GetResponse() }catch{} UpDir $d.FullName $c } foreach($f in Get-ChildItem $ld -File){ $rf="$rd/$($f.Name)" [void](UpFile $f.FullName $rf) } } Set-Content -Path $Log -Value "=== upload start $(Get-Date -Format 'HH:mm:ss') ===" -Encoding UTF8 if(-not (Test-Path $Stage)){ L "STAGING_MISSING"; exit 1 } # delete welcome page first $dr=New-FtpReq "/wwwroot/default.html" ([System.Net.WebRequestMethods+Ftp]::DeleteFile) 30000 try{ $null=$dr.GetResponse(); L "DELETED default.html" }catch{ L "default.html not present" } $mr=New-FtpReq $RemoteRoot ([System.Net.WebRequestMethods+Ftp]::MakeDirectory) 30000 try{ $null=$mr.GetResponse() }catch{} UpDir $Stage $RemoteRoot if($fail){ L "RESULT=PARTIAL_FAIL" } else { L "RESULT=OK" } L "=== upload end ==="