param( [Parameter(Mandatory = $true)][string]$FtpHost, [Parameter(Mandatory = $true)][string]$FtpUser, [Parameter(Mandatory = $true)][string]$FtpPassword, [string]$RemoteDir = "/httpdocs", [string]$ProjectPath = "..\\GameList.csproj", [string]$Configuration = "Release", [string]$Runtime = "win-x64", [string]$PublishDir = "..\\artifacts\\publish", [switch]$SelfContained, [string]$WinScpPath = "WinSCP.com" ) <# .SYNOPSIS Publish the app and mirror the output to an FTP-deployed IIS site. .DESCRIPTION - Builds with dotnet publish. - Drops app_offline.htm to pause the IIS site while files upload. - Uses WinSCP (ftp) to mirror publish output into $RemoteDir (deletes extraneous remote files). - Removes app_offline.htm when done. .PREREQS - WinSCP.com available in PATH or pass -WinScpPath "C:\Path\To\WinSCP.com". - FTP user must have write/delete rights to $RemoteDir. - If you have RDP, you can still run this locally; the app_offline flag safely stops the app without touching the pool. .EXAMPLE pwsh ./scripts/deploy-ftp.ps1 ` -FtpHost "ftp.example.com" ` -FtpUser "deploy" ` -FtpPassword (Get-Content ./secrets/ftp.pwd -Raw) ` -RemoteDir "/httpdocs" ` -Configuration Release #> Set-StrictMode -Version Latest $ErrorActionPreference = "Stop" function Assert-Tool { param([string]$Name) if (-not (Get-Command $Name -ErrorAction SilentlyContinue)) { throw "Required tool '$Name' not found. Install it or point -WinScpPath to the executable." } } Assert-Tool "dotnet" Assert-Tool $WinScpPath Write-Host "1) Publishing..." -ForegroundColor Cyan New-Item -ItemType Directory -Force -Path $PublishDir | Out-Null $publishArgs = @("publish", $ProjectPath, "-c", $Configuration, "-r", $Runtime, "-o", $PublishDir) if (-not $SelfContained) { $publishArgs += "--self-contained=false" } dotnet @publishArgs $offlineFile = Join-Path $PublishDir "app_offline.htm" "

Updating…

Back in a moment.

" | Set-Content -Encoding UTF8 $offlineFile Write-Host "2) Syncing via WinSCP (FTP mirror with delete)..." -ForegroundColor Cyan $tempScript = New-TemporaryFile @" option batch continue option confirm off open ftp://$($FtpUser):$($FtpPassword.Replace("`n","").Replace("`r",""))@$FtpHost lcd $PublishDir cd $RemoteDir put app_offline.htm synchronize remote . -delete rm app_offline.htm exit "@ | Set-Content -Path $tempScript -Encoding UTF8 & $WinScpPath "/ini=nul" "/script=$tempScript" Remove-Item $tempScript -ErrorAction SilentlyContinue Write-Host "`nDone. If you want to explicitly bounce the app pool while on RDP:" -ForegroundColor Green Write-Host " Import-Module WebAdministration" Write-Host " Stop-WebAppPool 'YourAppPoolName'; Start-WebAppPool 'YourAppPoolName'" -ForegroundColor DarkGray