You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

PowerShell FTP脚本无法全部覆盖Azure Web App文件问题求助

排查FTP上传Azure Web App无法覆盖全部文件的问题

看起来你的脚本核心逻辑是对的,但几个细节问题导致了部分文件无法被覆盖/上传。我帮你梳理下关键问题点,再给出修正后的完整脚本:

核心问题分析

  1. 变量名拼写错误:你定义的是$appdirecotry,但后续切换目录用的是$appdirectory——虽然你说能部分上传,可能实际运行时改了,但这个笔误很容易导致路径异常,得先修正。
  2. 目录创建逻辑缺陷:当远程目录已经存在时,MakeDirectory方法会直接抛出异常,导致脚本中断,后面的文件完全没机会处理。这是最常见的"部分文件没覆盖"的原因。
  3. 缺少错误处理:脚本没有任何异常捕获,只要某个文件/目录处理失败,整个流程就停了,剩下的文件自然不会被上传。
  4. 相对路径的潜在问题Resolve-Path -Relative返回的路径开头会带./,虽然多数FTP服务器能处理,但偶尔会导致路径识别混乱,比如把./file.txt当成根目录下的特殊路径。

修正后的脚本

# Get publishing profile for the web app
$webappname = "sib"
$resourceGroup = "sib2"
$appdirectory = "c:\temp\sib"  # 修正变量名拼写错误
$xml = [xml](Get-AzureRmWebAppPublishingProfile -Name $webappname `
-ResourceGroupName $resourceGroup `
-OutputFile null)
$xml = [xml]$xml

# Extract connection information from publishing profile
$username = $xml.SelectNodes("//publishProfile[@publishMethod=`"FTP`"]/@userName").value
$password = $xml.SelectNodes("//publishProfile[@publishMethod=`"FTP`"]/@userPWD").value
$url = $xml.SelectNodes("//publishProfile[@publishMethod=`"FTP`"]/@publishUrl").value

Write-Host "Setting working directory to $appdirectory"
Set-Location $appdirectory

$webclient = New-Object -TypeName System.Net.WebClient
$webclient.Credentials = New-Object System.Net.NetworkCredential($username,$password)
$files = Get-ChildItem -Path $appdirectory -Recurse

foreach ($file in $files) {
    # 处理相对路径:去掉开头的./,并转换为FTP格式的斜杠
    $relativepath = (Resolve-Path -Path $file.FullName -Relative).Replace('\', '/').TrimStart('./')
    $uri = New-Object System.Uri("$url/$relativepath")

    if($file.PSIsContainer) {
        Write-Host "Processing directory: $($uri.AbsolutePath)"
        try {
            # 先尝试列出目录,判断是否存在(避免重复创建抛出错误)
            $ftprequest = [System.Net.FtpWebRequest]::Create($uri);
            $ftprequest.Method = [System.Net.WebRequestMethods+Ftp]::ListDirectory
            $ftprequest.Credentials = New-Object System.Net.NetworkCredential($username,$password)
            $response = $ftprequest.GetResponse();
            $response.Close()
            Write-Host "Directory already exists, skipping creation"
        } catch [System.Net.WebException] {
            # 如果抛出"文件不存在"错误,说明目录需要创建
            if ($_.Exception.Response.StatusCode -eq [System.Net.FtpStatusCode]::ActionNotTakenFileUnavailable) {
                $ftprequest = [System.Net.FtpWebRequest]::Create($uri);
                $ftprequest.Method = [System.Net.WebRequestMethods+Ftp]::MakeDirectory
                $ftprequest.UseBinary = $true
                $ftprequest.UsePassive = $true  # 启用被动模式,适配多数网络环境
                $ftprequest.Credentials = New-Object System.Net.NetworkCredential($username,$password)
                $response = $ftprequest.GetResponse();
                Write-Host "Created directory successfully: $($response.StatusDescription)"
                $response.Close()
            } else {
                Write-Host "Warning: Failed to handle directory $($uri.AbsolutePath): $($_.Exception.Message)"
            }
        }
        continue
    }

    try {
        Write-Host "Uploading $($file.FullName) to $($uri.AbsoluteUri)"
        # WebClient.UploadFile默认使用STOR命令,会直接覆盖已存在的文件
        $webclient.UploadFile($uri, $file.FullName)
        Write-Host "Upload succeeded"
    } catch {
        Write-Host "Warning: Failed to upload $($file.FullName): $($_.Exception.Message)"
        # 捕获错误后继续处理下一个文件,不中断流程
        continue
    }
}

$webclient.Dispose()
Write-Host "All files processed!"

额外优化建议

  1. 启用被动模式:我在脚本里打开了UsePassive = $true,Azure的FTP服务器推荐用被动模式,能避免很多防火墙/网络连接问题。
  2. 处理文件锁定:如果某些文件还是无法覆盖,大概率是Web App正在占用这些文件(比如应用处于运行状态),可以先停掉App再上传:
    # 停止Web App
    Stop-AzureRmWebApp -Name $webappname -ResourceGroupName $resourceGroup
    # ... 执行上传逻辑 ...
    # 重启Web App
    Start-AzureRmWebApp -Name $webappname -ResourceGroupName $resourceGroup
    
  3. 换用更可靠的部署方式:FTP其实不是Azure推荐的部署方式,你可以试试Zip部署,效率更高也更稳定:
    Publish-AzureRmWebApp -ResourceGroupName $resourceGroup -Name $webappname -ArchivePath (Get-Item $appdirectory).FullName -Force
    

内容的提问来源于stack exchange,提问作者Sibghatullah Sheikh

火山引擎 最新活动