Background
In the BizTalk installation documentation it outlines the fact that you need WinSCP. Michael Stephenson wrote a great article that goes into the how and why. He also included a simple script to automatically install the right version.
UPDATE: This script now automatically detects BizTalk Server 2020, BizTalk Server 2016 Cumulative Update 5 and the older versions of BizTalk Server 2016 before Cumulative Update 5 and downloads and installs the correct version. Thanks to Nicolas Blatter, a good friend, fellow former VTS and integration export who pointed out the change in behavior.
UPDATE: This script was re-written to handle BizTalk Server 2020, but also Cumulative Update 7 which changed the WinSCP Version. This was a significant rewrite to more properly handle environments that have Feature Pack 1, 2 and 3 and the latest cumulative updates.
Solution
As I love to script, I wanted to build something that was a little more robust and flexible. Here is the extended script which tries to figure out as much as possible automatically and gives error messages that might help you track down the problem.
#Parameters
Param([Parameter(Mandatory = $false)][string]$nugetDownloadFolder = (Get-Item Env:TEMP).Value + "\nuget")
Write-Debug ('$nugetDownloadFolder :' + $nugetDownloadFolder)
$Continue = $true
function SearchForCU {
# Parameter help description
Param([string] $CumulativeUpdateID)
Write-Debug "Checking for CU $CumulativeUpdateID"
$CUFound = $false
$CUNameTemplate = "*BizTalk Server 2016 *KB*$CumulativeUpdateID*"
Write-Debug "Cumulative Update Template $CUNameTemplate"
$SearchResult = Get-ChildItem -path HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\ -Recurse -ErrorAction SilentlyContinue | Where-Object { $_.Name -like $CUNameTemplate }
if ($SearchResult) {
Write-Host "Found BizTalk Cumulative Update " SearchResult.GetValue("DisplayName")
$CUFound = $true
}
return $CUFound
}
$consoleWidth = $Host.UI.RawUI.WindowSize.Width - 2
$upString = "^" * $consoleWidth
$hashString = "#" * $consoleWidth
$bangString = "!" * $consoleWidth
$equalString = "=" * $consoleWidth
Write-Host $equalString
$nugetDownloadFolderExists = Test-Path $nugetDownloadFolder
if (-not $nugetDownloadFolderExists) {
Write-Host $hashString
Write-Debug ('The $nugetDownloadFolder doesn`t exist, creating the folder ' + $nugetDownloadFolder)
New-Item -Path $nugetDownloadFolder -ItemType "Directory"
}
$nugetDownloadFolderExists = Test-Path $nugetDownloadFolder
if (-not $nugetDownloadFolderExists) {
$Continue = $false
Write-Error $bangString
Write-Error "An attempt to use the '" $nugetDownloadFolder "' directory for a download target failed."
}
if ($Continue) {
$bizTalkInstallFolder = (Get-Item Env:BTSINSTALLPATH).Value
if (-not $bizTalkInstallFolder) {
Write-Debug ('The Env:BTSINSTALLPATH doesn`t exist, checking to see if the path is in the registry HKLM:\SOFTWARE\Microsoft\BizTalk Server\3.0@InstallPath')
$bizTalkInstallFolder = (get-itemPropertyValue 'HKLM:\SOFTWARE\Microsoft\BizTalk Server\3.0' -Name 'InstallPath')
if (-not $bizTalkInstallFolder) {
Write-Error $bangString
Write-Error "BizTalk was not located by checking the environment variable BTSINSTALLPATH and"
Write-Error " the Registry key for BizTalk, exiting the process"
Write-Error "Confirm that BizTalk is installed"
Write-Error $upString
Write-Error $bangString
}
}
$bizTalkInstallFolderExists = Test-Path $bizTalkInstallFolder
if ($Continue -and -not $bizTalkInstallFolderExists) {
$Continue = $false
Write-Error "The BizTalk Installation was found in the registry"
Write-Error " The folder $bizTalkInstallFolder does not exist, "
Write-Error " even though it was discovered in the registry or the BTSINSTALLPATH environment setting"
Write-Error $upString
Write-Error $bangString
}
}
if ($Continue) {
$bizTalkProductCode = (get-itemPropertyValue 'HKLM:\SOFTWARE\Microsoft\BizTalk Server\3.0' -Name 'ProductCodeCurrent')
$bizTalkProductName = (get-itemPropertyValue 'HKLM:\SOFTWARE\Microsoft\BizTalk Server\3.0' -Name 'ProductName')
$bizTalkProductVer = (get-itemPropertyValue 'HKLM:\SOFTWARE\Microsoft\BizTalk Server\3.0' -Name 'ProductVersion')
Write-Host $hashString
Write-Host "Located $bizTalkProductName and verion $bizTalkProductVer"
Write-Host " installed in $bizTalkInstallFolder"
Write-Host $hashString
$winSCPVersion = "5.7.7"
if ($bizTalkProductCode -eq '{205F5836-7512-4A06-9E74-ADC8AFA0EEC5}') {
# BizTalk Server 2020
#CU name Build version KB number Release day WinSCP Version
#NonUC 3.13.717.0 NA January 15, 2020 WinSCP 5.15.4
Write-Host $hashString
$winSCPVersion = "5.15.4"
Write-Host "Detected BizTalk Server 2020 and this download process will use WinSCP $winSCPVersion"
}
elseif ($bizTalkProductCode -eq '{B084F3A7-3E8F-4E7B-B673-EED1715D28ED}') {
Write-Host $hashString
Write-Host "Detected BizTalk Server 2016, testing to see which Cumulative Update is installed"
Write-Host $hashString
# BizTalk Server 2016
#
#CU name Build version KB number Release day WinSCP Version
#CU7 3.12.859.2 4528776 January 22, 2020 WinSCP 5.15.9
#CU6 3.12.843.2 4477494 February 28, 2019 WinSCP 5.13.1
#CU5 3.12.834.2 4132957 June 25, 2018 WinSCP 5.13.1
#CU4 3.12.823.2 4051353 January 30, 2018 WinSCP 5.7.7
#CU3 3.12.815.2 4039664 September 01, 2017 WinSCP 5.7.7
#CU2 3.12.807.2 4021095 May 26, 2017 WinSCP 5.7.7
#CU1 3.12.796.2 3208238 January 26, 2017 WinSCP 5.7.7
#NonCU 3.12.xxx.x NA October 11, 2016 WinSCP 5.7.7
$CUfound = $false
Write-Host $hashString
if (SearchForCU("4536185")) {
# running BizTalk Server 2016 CU7 and FP 3 with new WinSCP Version
$winSCPVersion = "5.15.9"
Write-Host "Detected BizTalk Server 2016 with CU7 and FP3 and this download process will use WinSCP $winSCPVersion"
$CUFound = $true
}
elseif (SearchForCU("4528776")) {
# running BizTalk Server 2016 CU7 with new WinSCP Version
$winSCPVersion = "5.15.9"
Write-Host "Detected BizTalk Server 2016 with CU7 and this download process will use WinSCP $winSCPVersion"
$CUFound = $true
}
elseif (SearchForCU("4294900")) {
# running BizTalk Server 2016 CU6 and FP 3 with new WinSCP Version
$winSCPVersion = "5.13.1"
Write-Host "Detected BizTalk Server 2016 with CU6 and this download process will use WinSCP $winSCPVersion"
$CUFound = $true
}
elseif (SearchForCU("4477494")) {
# running BizTalk Server 2016 CU6 with new WinSCP Version
$winSCPVersion = "5.13.1"
Write-Host "Detected BizTalk Server 2016 with CU6 and this download process will use WinSCP $winSCPVersion"
$CUFound = $true
}
elseif (SearchForCU("4132957")) {
# running BizTalk Server 2016 CU5 with new WinSCP Version
$winSCPVersion = "5.13.1"
Write-Host "Detected BizTalk Server 2016 with CU5 and this download process will use WinSCP $winSCPVersion"
$CUFound = $true
}
elseif (SearchForCU("4051353")) {
# running BizTalk Server 2016 CU4, using original WinSCP Version
$winSCPVersion = "5.7.7"
Write-Host "Detected BizTalk Server 2016 with CU4, and this download process will use WinSCP $winSCPVersion"
$CUFound = $true
}
elseif (SearchForCU("4094130")) {
# running BizTalk Server 2016 CU4, using original WinSCP Version
$winSCPVersion = "5.7.7"
Write-Host "Detected BizTalk Server 2016 with CU4, and this download process will use WinSCP $winSCPVersion"
$CUFound = $true
}
elseif (SearchForCU("4039664")) {
4536185
# running BizTalk Server 2016 CU3, using original WinSCP Version
$winSCPVersion = "5.7.7"
Write-Host "Detected BizTalk Server 2016 with CU3, and this download process will use WinSCP $winSCPVersion"
$CUFound = $true
}
elseif (SearchForCU("4054819")) {
4536185
# running BizTalk Server 2016 CU3, using original WinSCP Version
$winSCPVersion = "5.7.7"
Write-Host "Detected BizTalk Server 2016 with CU3, and this download process will use WinSCP $winSCPVersion"
$CUFound = $true
}
elseif (SearchForCU("4014788")) {
4536185
# running BizTalk Server 2016 CU3, using original WinSCP Version
$winSCPVersion = "5.7.7"
Write-Host "Detected BizTalk Server 2016 with CU3, and this download process will use WinSCP $winSCPVersion"
$CUFound = $true
}
elseif (SearchForCU("4021095")) {
# running BizTalk Server 2016 CU2, using original WinSCP Version
$winSCPVersion = "5.7.7"
Write-Host "Detected BizTalk Server 2016 with CU2, and this download process will use WinSCP $winSCPVersion"
$CUFound = $true
}
elseif (SearchForCU("3208238")) {
# running BizTalk Server 2016 CU1, using original WinSCP Version
$winSCPVersion = "5.7.7"
Write-Host "Detected BizTalk Server 2016 with CU1, and this download process will use WinSCP $winSCPVersion"
$CUFound = $true
}
}
if (-not $CUFound) {
# running BizTalk Server 2016 without any Cumulative Updates, using original WinSCP Version
$winSCPVersion = "5.7.7"
Write-Host "Detected BizTalk Server 2016 with no cumulative updates installed, and this download process will use WinSCP $winSCPVersion"
}
if ($winSCPVersion -eq "5.15.9") {
$winSCPexe = "WinSCP.5.15.9\tools\WinSCP.exe"
$winSCPdll = "WinSCP.5.15.9\lib\net\WinSCPnet.dll"
}
elseif ($winSCPVersion -eq "5.15.4") {
$winSCPexe = "WinSCP.5.15.4\tools\WinSCP.exe"
$winSCPdll = "WinSCP.5.15.4\lib\net\WinSCPnet.dll"
}
elseif ($winSCPVersion -eq "5.13.1") {
$winSCPexe = "WinSCP.5.13.1\tools\WinSCP.exe"
$winSCPdll = "WinSCP.5.13.1\lib\net\WinSCPnet.dll"
}
elseif ($winSCPVersion -eq "5.7.7") {
$WinSCPexe = "WinSCP.5.7.7\content\WinSCP.exe"
$winSCPdll = "WinSCP.5.7.7\lib\WinSCPnet.dll"
}
}
if ($Continue) {
#Download NuGet
$sourceNugetExe = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
Write-Host $hashString
Write-Host "Downloading Nuget from $sourceNugetExe and storing it in the folder $nugetDownloadFolder"
$targetNugetExe = "$nugetDownloadFolder\nuget.exe"
Write-Debug "Invoke-WebRequest $sourceNugetExe -OutFile $targetNugetExe"
Invoke-WebRequest $sourceNugetExe -OutFile $targetNugetExe
$targetNugetExeExists = Test-Path $targetNugetExe
if (-not $targetNugetExeExists) {
$Continue = $false
Write-Error "The download of the Nuget EXE from " $sourceNugetExe " did not succeed"
Write-Error $bangString
}
}
if ($Continue) {
#Download the right version of WinSCP
Write-Host $hashString
Write-Host "Downloading WinSCP version $winSCPVersion from NuGet $sourceNugetExe and storing it in $nugetDownloadFolder"
Write-Debug "$getWinSCP = '$targetNugetExe' Install WinSCP -Version $winSCPVersion -OutputDirectory '$nugetDownloadFolder'"
$getWinSCP = "'$targetNugetExe' Install WinSCP -Version $winSCPVersion -OutputDirectory '$nugetDownloadFolder'"
Write-Debug "Invoke-Expression `"& $getWinSCP"
Invoke-Expression "& $getWinSCP"
$WinSCPDownload = "$nugetDownloadFolder\$winSCPexe"
$WinSCPDllDownload = "$nugetDownloadFolder\$winSCPdll"
$WinSCPExists = Test-Path $WinSCPDownload
$WinSCPDLLExists = Test-Path $WinSCPDllDownload
if (-not $WinSCPExists -or -not $WinSCPDLLExists) {
$Continue = $false
Write-Error "WinSCP $winSCPVersion was not properly downloaded"
Write-Error $bangString
}
}
if ($Continue) {
#Copy WinSCP items to BizTalk Folder
Write-Host $hashString
Write-Host "Copying WinSCP version $winSCPVersion to BizTalk Folder"
write-debug "Copy-Item $WinSCPDownload $bizTalkInstallFolder"
Copy-Item $WinSCPDownload $bizTalkInstallFolder
write-debug "Copy-Item $WinSCPDllDownload $bizTalkInstallFolder"
Copy-Item $WinSCPDllDownload $bizTalkInstallFolder
$WinSCPBTSExists = Test-Path "$bizTalkInstallFolder\WinSCP.exe"
$WinSCPDLLBTSExists = Test-Path "$biztalkInstallFolder\WinSCPnet.dll"
if (-not $WinSCPBTSExists) {
$Continue = $false
Write-Error "The WinSCP.exe file version $winSCPVersion was not properly copied to the target folder " $bizTalkInstallFolder
Write-Error $bangString
}
if (-not $WinSCPDLLBTSExists) {
$Continue = $false
Write-Error "The WinSCPnet.dll file version $winSCPVersion was not properly copied to the target folder " $bizTalkInstallFolder
Write-Error $bangString
}
}
if (-not $Continue) {
Write-Error $bangString
Write-Error "Something went wrong during installation and the installation is not working"
Write-Error "Please inspect the errors above and resolve them"
Write-Error "Exiting"
Write-Error $bangString
}
else {
Write-Host $hashString
Write-Host -ForegroundColor Green "WinSCP has been properly installed for BizTalk's SFTP Adapter"
Write-Host -ForegroundColor Green $upString
Write-Host $equalString
}