Set-StrictMode -Version Latest [string] $script:platform = $env:PROCESSOR_ARCHITECTURE [string] $script:vcPath = $null [System.IO.DirectoryInfo] $script:OpenSSHRoot = $null [System.IO.DirectoryInfo] $script:gitRoot = $null [bool] $script:Verbose = $false [string] $script:BuildLogFile = $null <# Called by Write-BuildMsg to write to the build log, if it exists. #> function Write-Log { param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $Message ) # write it to the log file, if present. if (-not ([string]::IsNullOrEmpty($script:BuildLogFile))) { Add-Content -Path $script:BuildLogFile -Value $Message } } <# .Synopsis Writes a build message. .Parameter Message The message to write. .Parameter AsInfo Writes a user message using Write-Information. .Parameter AsVerbose Writes a message using Write-Verbose and to the build log if -Verbose was specified to Start-DscBuild. .Parameter AsWarning Writes a message using Write-Warning and to the build log. .Parameter AsError Writes a message using Write-Error and to the build log. .Parameter Silent Writes the message only to the log. .Parameter ErrorAction Determines if the script is terminated when errors are written. This parameter is ignored when -Silent is specified. .Example Write-BuildMsg -AsInfo 'Starting the build' Writes an informational message to the log and to the user .Example Write-BuildMsg -AsError 'Terminating build' -Silent Writes an error message only to the log .Example Write-BuildMsg -AsError 'Terminating build' -ErrorAction Stop Writes an error message to the log and the user and terminates the build. .Example Write-BuildMsg -AsInfo 'Nuget is already installed' -Silent:(-not $script:Verbose) Writes an informational message to the log. If -Verbose was specified, also writes to message to the user. #> function Write-BuildMsg { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $Message, [Parameter(ParameterSetName='Info')] [switch] $AsInfo, [Parameter(ParameterSetName='Verbose')] [switch] $AsVerbose, [Parameter(ParameterSetName='Warning')] [switch] $AsWarning, [Parameter(ParameterSetName='Error')] [switch] $AsError, [switch] $Silent ) if ($AsVerbose) { if ($script:Verbose) { Write-Log -Message "VERBOSE: $message" if (-not $Silent) { Write-Verbose -Message $message -Verbose } } return } if ($AsInfo) { Write-Log -Message "INFO: $message" if (-not $Silent) { Write-Information -MessageData $message -InformationAction Continue } return } if ($AsWarning) { Write-Log -Message "WARNING: $message" if (-not $Silent) { Write-Warning -Message $message } return } if ($AsError) { Write-Log -Message "ERROR: $message" if (-not $Silent) { Write-Error -Message $message } return } # if we reached here, no output type switch was specified. Write-BuildMsg -AsError -ErrorAction Stop -Message 'Write-BuildMsg was called without selecting an output type.' } <# .Synopsis Verifies all tools and dependencies required for building Open SSH are installed on the machine. #> function Start-SSHBootstrap { [bool] $silent = -not $script:Verbose Set-StrictMode -Version Latest Write-BuildMsg -AsInfo -Message "Checking tools and dependencies" -Silent:$silent $machinePath = [Environment]::GetEnvironmentVariable('Path', 'MACHINE') $newMachineEnvironmentPath = $machinePath # Install chocolatey $chocolateyPath = "$env:AllUsersProfile\chocolatey\bin" if(Get-Command "choco" -ErrorAction SilentlyContinue) { Write-BuildMsg -AsVerbose -Message "Chocolatey is already installed. Skipping installation." -Silent:$silent } else { Write-BuildMsg -AsInfo -Message "Chocolatey not present. Installing chocolatey." -Silent:$silent Invoke-Expression ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')) 2>&1 >> $script:BuildLogFile if (-not ($machinePath.ToLower().Contains($chocolateyPath.ToLower()))) { Write-BuildMsg -AsVerbose -Message "Adding $chocolateyPath to Path environment variable" -Silent:$silent $newMachineEnvironmentPath += ";$chocolateyPath" $env:Path += ";$chocolateyPath" } else { Write-BuildMsg -AsVerbose -Message "$chocolateyPath already present in Path environment variable" -Silent:$silent } } # Add git\cmd to the path $gitCmdPath = "$env:ProgramFiles\git\cmd" if (-not ($machinePath.ToLower().Contains($gitCmdPath.ToLower()))) { Write-BuildMsg -AsVerbose -Message "Adding $gitCmdPath to Path environment variable" -Silent:$silent $newMachineEnvironmentPath = "$gitCmdPath;$newMachineEnvironmentPath" } else { Write-BuildMsg -AsVerbose -Message "$gitCmdPath already present in Path environment variable" -Silent:$silent } $nativeMSBuildPath = "${env:ProgramFiles(x86)}\MSBuild\14.0\bin" if($script:platform -ieq "AMD64") { $nativeMSBuildPath += "\amd64" } if (-not ($machinePath.ToLower().Contains($nativeMSBuildPath.ToLower()))) { Write-BuildMsg -AsVerbose -Message "Adding $nativeMSBuildPath to Path environment variable" -Silent:$silent $newMachineEnvironmentPath += ";$nativeMSBuildPath" $env:Path += ";$nativeMSBuildPath" } else { Write-BuildMsg -AsVerbose -Message "$nativeMSBuildPath already present in Path environment variable" -Silent:$silent } # Update machine environment path if ($newMachineEnvironmentPath -ne $machinePath) { [Environment]::SetEnvironmentVariable('Path', $newMachineEnvironmentPath, 'MACHINE') } # install nasm $packageName = "nasm" $nasmPath = "${env:ProgramFiles(x86)}\NASM" if (-not (Test-Path -Path $nasmPath -PathType Container)) { Write-BuildMsg -AsInfo -Message "$packageName not present. Installing $packageName." -Silent:$silent choco install $packageName -y --force --limitoutput --execution-timeout 10000 2>&1 >> $script:BuildLogFile } else { Write-BuildMsg -AsVerbose -Message "$packageName present. Skipping installation." -Silent:$silent } # Install Visual Studio 2015 Community $packageName = "VisualStudio2015Community" $VSPackageInstalled = Get-ItemProperty "HKLM:\software\WOW6432Node\Microsoft\VisualStudio\14.0\setup\vs" -ErrorAction SilentlyContinue if ($null -eq $VSPackageInstalled) { Write-BuildMsg -AsInfo -Message "$packageName not present. Installing $packageName." $adminFilePath = "$script:OpenSSHRoot\contrib\win32\openssh\VSWithBuildTools.xml" choco install $packageName -packageParameters "--AdminFile $adminFilePath" -y --force --limitoutput --execution-timeout 10000 2>&1 >> $script:BuildLogFile } else { Write-BuildMsg -AsVerbose -Message "$packageName present. Skipping installation." -Silent:$silent } # Install Windows 8.1 SDK $packageName = "windows-sdk-8.1" $sdkPath = "C:\Program Files (x86)\Windows Kits\8.1\bin\x86\register_app.vbs" if (-not (Test-Path -Path $sdkPath)) { Write-BuildMsg -AsInfo -Message "Windows 8.1 SDK not present. Installing $packageName." choco install $packageName -y --limitoutput --force 2>&1 >> $script:BuildLogFile } else { Write-BuildMsg -AsInfo -Message "$packageName present. Skipping installation." -Silent:$silent } # Require restarting PowerShell session if ($null -eq $VSPackageInstalled) { Write-Host "To apply changes, please close this PowerShell window, open a new one and call Start-SSHBuild or Start-DscBootstrap again." -ForegroundColor Black -BackgroundColor Yellow Write-Host -NoNewLine 'Press any key to close this PowerShell window...' -ForegroundColor Black -BackgroundColor Yellow $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown') exit } # Ensure the VS C toolset is installed if ($null -eq $env:VS140COMNTOOLS) { Write-BuildMsg -AsError -ErrorAction Stop -Message "Cannot find Visual Studio 2015 Environment variable VS140COMNTOOlS" } $item = Get-Item(Join-Path -Path $env:VS140COMNTOOLS -ChildPath '../../vc') $script:vcPath = $item.FullName Write-BuildMsg -AsVerbose -Message "vcPath: $script:vcPath" -Silent:$silent if ((Test-Path -Path "$script:vcPath\vcvarsall.bat") -eq $false) { Write-BuildMsg -AsError -ErrorAction Stop -Message "Could not find Visual Studio vcvarsall.bat at" + $script:vcPath } } function Clone-Win32OpenSSH { [bool] $silent = -not $script:Verbose $win32OpenSSHPath = join-path $script:gitRoot "Win32-OpenSSH" if (-not (Test-Path -Path $win32OpenSSHPath -PathType Container)) { Write-BuildMsg -AsInfo -Message "clone repo Win32-OpenSSH" -Silent:$silent Push-Location $gitRoot git clone -q --recursive https://github.com/PowerShell/Win32-OpenSSH.git $win32OpenSSHPath Pop-Location } Write-BuildMsg -AsInfo -Message "pull latest from repo Win32-OpenSSH" -Silent:$silent Push-Location $win32OpenSSHPath git fetch -q origin git checkout -qf L1-Prod Pop-Location } function Copy-OpenSSLSDK { [bool] $silent = -not $script:Verbose $sourcePath = Join-Path $script:gitRoot "Win32-OpenSSH\contrib\win32\openssh\OpenSSLSDK" Write-BuildMsg -AsInfo -Message "copying $sourcePath" -Silent:$silent Copy-Item -Container -Path $sourcePath -Destination $PSScriptRoot -Recurse -Force -ErrorAction SilentlyContinue -ErrorVariable e if($e -ne $null) { Write-BuildMsg -AsError -ErrorAction Stop -Message "Copy OpenSSL from $sourcePath failed " } } function Start-SSHBuild { [CmdletBinding(SupportsShouldProcess=$false)] param ( [ValidateSet('x86', 'x64')] [string]$NativeHostArch = "x64", [ValidateSet('Debug', 'Release', '')] [string]$Configuration = "Release" ) Set-StrictMode -Version Latest $script:BuildLogFile = $null [System.IO.DirectoryInfo] $repositoryRoot = Get-RepositoryRoot # Get openssh-portable root $script:OpenSSHRoot = Get-Item -Path $repositoryRoot.FullName $script:gitRoot = split-path $script:OpenSSHRoot if($PSBoundParameters.ContainsKey("Verbose")) { $script:Verbose = ($PSBoundParameters['Verbose']).IsPresent } [bool] $silent = -not $script:Verbose $script:BuildLogFile = Get-BuildLogFile -root $repositoryRoot.FullName -Configuration $Configuration -NativeHostArch $NativeHostArch if (Test-Path -Path $script:BuildLogFile) { Remove-Item -Path $script:BuildLogFile -force } Write-BuildMsg -AsInfo -Message "Starting Open SSH build; Build Log: $($script:BuildLogFile)" Start-SSHBootstrap Clone-Win32OpenSSH Copy-OpenSSLSDK $msbuildCmd = "msbuild.exe" $solutionFile = Get-SolutionFile -root $repositoryRoot.FullName $cmdMsg = @("${solutionFile}", "/p:Platform=${NativeHostArch}", "/p:Configuration=${Configuration}", "/m", "/noconlog", "/nologo", "/fl", "/flp:LogFile=${script:BuildLogFile}`;Append`;Verbosity=diagnostic") & $msbuildCmd $cmdMsg $errorCode = $LASTEXITCODE if ($errorCode -ne 0) { Write-BuildMsg -AsError -ErrorAction Stop -Message "Build failed for OpenSSH.`nExitCode: $error." } Write-BuildMsg -AsInfo -Message "SSH build passed." -Silent:$silent } function Get-BuildLogFile { param ( [Parameter(Mandatory=$true)] [ValidateNotNull()] [System.IO.DirectoryInfo] $root, [ValidateSet('x86', 'x64')] [string]$NativeHostArch = "x64", [ValidateSet('Debug', 'Release', '')] [string]$Configuration = "Release" ) return Join-Path -Path $root -ChildPath "contrib\win32\openssh\OpenSSH$($Configuration)$($NativeHostArch).log" } function Get-SolutionFile { param ( [Parameter(Mandatory=$true)] [ValidateNotNull()] [System.IO.DirectoryInfo] $root ) return Join-Path -Path $root -ChildPath "contrib\win32\openssh\Win32-OpenSSH.sln" } <# .Synopsis Finds the root of the git repository .Outputs A System.IO.DirectoryInfo for the location of the root. .Inputs None .Notes FileNotFoundException is thrown if the current directory does not contain a CMakeLists.txt file. #> function Get-RepositoryRoot { Set-StrictMode -Version Latest $currentDir = (Get-Item -Path $PSCommandPath).Directory while ($null -ne $currentDir.Parent) { $path = Join-Path -Path $currentDir.FullName -ChildPath '.git' if (Test-Path -Path $path) { return $currentDir } $currentDir = $currentDir.Parent } throw new-object System.IO.DirectoryNotFoundException("Could not find the root of the GIT repository") } Export-ModuleMember -Function Start-SSHBuild, Get-RepositoryRoot, Get-BuildLogFile, Clone-Win32OpenSSH, Copy-OpenSSLSDK, Write-BuildMsg