<# .SYNOPSIS Configures IIS and installs the Remotely server. .COPYRIGHT Copyright © 2020 Translucency Software. All rights reserved. #> param ( # The name to use for the IIS Application Pool for the Remotely site. [Parameter(Mandatory=$True)] [string]$AppPoolName, # The name to use for the IIS site. [Parameter(Mandatory=$True)] [string]$SiteName, # The folder path where the Remotely server files should be located. [Parameter(Mandatory=$True)] [string]$SitePath, # The hostname that IIS will use for the site (e.g. remotely.mydomain.com). [Parameter(Mandatory=$True)] [string]$BindingHostname, # Whether to run the script without any prompts. [switch]$Quiet, # The path to Windows ACME Simple (wacs.exe) to use for automatically obtaining and # installing a Let's Encrypt certificate. # (Project and downloads: https://github.com/win-acme/win-acme) [string]$WacsPath, # The email address to use when registering the certificate with WACS. [string]$EmailAddress ) [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $ErrorActionPreference = "Stop" $Host.UI.RawUI.WindowTitle = "Remotely Setup" Clear-Host #region Variables $ServerCmdlets = $false $FirewallSet = $false $CopyErrors = $false if ($PSScriptRoot -eq ""){ $PSScriptRoot = (Get-Location) } $Root = (Get-Item -Path $PSScriptRoot).Parent.FullName #endregion #region Functions function Do-Pause { if (!$Quiet){ pause } } function Wrap-Host { [CmdletBinding()] [Alias()] [OutputType([int])] Param ( # The text to write. [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, Position=0)] [String] $Text, # Param2 help description [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, Position=1)] [ConsoleColor] $ForegroundColor ) Begin { } Process { if (!$Text){ Write-Host return } $Width = $Host.UI.RawUI.BufferSize.Width $SB = New-Object System.Text.StringBuilder while ($Text.Length -gt $Width) { [int]$LastSpace = $Text.Substring(0, $Width).LastIndexOf(" ") $SB.AppendLine($Text.Substring(0, $LastSpace).Trim()) | Out-Null $Text = $Text.Substring(($LastSpace), $Text.Length - $LastSpace).Trim() } $SB.Append($Text) | Out-Null if ($ForegroundColor) { Write-Host $SB.ToString() -ForegroundColor $ForegroundColor } else { Write-Host $SB.ToString() } } End { } } #endregion #region Prerequisite Tests ### Test if process is elevated. ### $User = [Security.Principal.WindowsIdentity]::GetCurrent() if ((New-Object Security.Principal.WindowsPrincipal $User).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) -eq $false) { Wrap-Host Wrap-Host "Error: This installation needs to be run from an elevated process (Run as Administrator)." -ForegroundColor Red Do-Pause return } ### Check PS version. ### if ((Get-Host).Version.Major -lt 5) { Wrap-Host Wrap-Host "Error: PowerShell 5 is required. Please install it via the Windows Management Framework 5.1 download from Microsoft." -ForegroundColor Red Do-Pause return } ### Check Script Root ### if (!$PSScriptRoot) { Wrap-Host Wrap-Host "Error: Unable to determine working directory. Please make sure you're running the full script and not just a section." -ForegroundColor Red Do-Pause return } ### Check OS version. ### $OS = Get-WmiObject -Class Win32_OperatingSystem if ($OS.Name.ToLower().Contains("home") -or $OS.Caption.ToLower().Contains("home")) { Wrap-Host Wrap-Host "Error: Windows Home version does not have the necessary features to run Remotely." -ForegroundColor Red Do-Pause return } ### Test if Windows Feature cmdlets are available. ### if ((Get-Command -Name "Add-WindowsFeature" -ErrorAction Ignore) -eq $null) { $ServerCmdlets = $false } else { $ServerCmdlets = $true } ### Check if PostgreSQL is installed. ### ##if ((Get-Package -Name "*PostgreSQL*" -ErrorAction SilentlyContinue) -eq $null){ ## Wrap-Host ## Wrap-Host "ERROR: PostgreSQL was not found. Please install it from https://postgresql.org." -ForegroundColor Red ## Wrap-Host ## Do-Pause ## return ##} if ((Get-Package -Name "*3.1.2 - Windows Server Hosting*" -ErrorAction SilentlyContinue) -eq $null){ Wrap-Host "Downloading .NET Core Runtime and Hosting Bundle..." $ProgressPreference = "SilentlyContinue" Invoke-WebRequest -Uri "https://download.visualstudio.microsoft.com/download/pr/dd119832-dc46-4ccf-bc12-69e7bfa61b18/990843c6e0cbd97f9df68c94f6de6bb6/dotnet-hosting-3.1.2-win.exe" -OutFile "$env:TEMP\dotnet-hosting-3.1.2-win.exe" $ProgressPreference = "Continue" Start-Process -FilePath "$env:TEMP\dotnet-hosting-3.1.2-win.exe" -ArgumentList "/install /quiet /norestart" -Wait Wrap-Host Wrap-Host ".NET Runtime installation completed." } #endregion ### Hosting Requirements ### Wrap-Host Wrap-Host "**********************************" Wrap-Host " IMPORTANT" -ForegroundColor Green Wrap-Host "**********************************" Wrap-Host Wrap-Host "You must have the .NET Core Runtime installed, which includes the IIS hosting module. The SDK doesn't have this." Wrap-Host Wrap-Host "If you have not already done so, please download and install it from the following link:" Wrap-Host Wrap-Host "https://dotnet.microsoft.com/download" Wrap-Host Do-Pause Clear-Host ### Intro ### Clear-Host Wrap-Host Wrap-Host "**********************************" Wrap-Host " Remotely Setup" -ForegroundColor Cyan Wrap-Host "**********************************" Wrap-Host Wrap-Host "Hello, and thank you for trying out Remotely!" -ForegroundColor Green Wrap-Host Wrap-Host "This setup script will create an IIS site and install Remotely on this machine." -ForegroundColor Green Wrap-Host Wrap-Host "If you encounter any problems or have any questions, please contact Translucency_Software@outlook.com." -ForegroundColor Green Wrap-Host Do-Pause Clear-Host ### Automatic IIS Setup ### if ($ServerCmdlets) { $RebootRequired = $false Wrap-Host Wrap-Host "Installing IIS components..." -ForegroundColor Green Write-Progress -Activity "IIS Component Installation" -Status "Installing web server" -PercentComplete (1/7*100) $Result = Add-WindowsFeature Web-Server if ($Result.RestartNeeded -like "Yes") { $RebootRequired = $true } #Write-Progress -Activity "IIS Component Installation" -Status "Installing ASP.NET" -PercentComplete (2/7*100) #$Result = Add-WindowsFeature Web-Asp-Net #if ($Result.RestartNeeded -like "Yes") #{ # $RebootRequired = $true #} #Write-Progress -Activity "IIS Component Installation" -Status "Installing ASP.NET 4.5" -PercentComplete (3/7*100) #$Result = Add-WindowsFeature Web-Asp-Net45 #if ($Result.RestartNeeded -like "Yes") #{ # $RebootRequired = $true #} #Write-Progress -Activity "IIS Component Installation" -Status "Installing web sockets" -PercentComplete (4/7*100) #$Result = Add-WindowsFeature Web-WebSockets #if ($Result.RestartNeeded -like "Yes") #{ # $RebootRequired = $true #} Write-Progress -Activity "IIS Component Installation" -Status "Installing IIS management tools" -PercentComplete (5/7*100) $Result = Add-WindowsFeature Web-Mgmt-Tools if ($Result.RestartNeeded -like "Yes") { $RebootRequired = $true } #Write-Progress -Activity "IIS Component Installation" -Status "Installing web filtering" -PercentComplete (6/7*100) #$Result = Add-WindowsFeature Web-Filtering #if ($Result.RestartNeeded -like "Yes") #{ # $RebootRequired = $true #} Write-Progress -Activity "IIS Component Installation" -Status "IIS setup completed" -PercentComplete (7/7*100) -Completed Start-Sleep 2 } else { Wrap-Host Wrap-Host "Installing IIS components..." -ForegroundColor Green Write-Progress -Activity "IIS Component Installation" -Status "Installing web server" -PercentComplete (1/7*100) DISM /Online /Enable-Feature /FeatureName:IIS-WebServer /All /Quiet #Write-Progress -Activity "IIS Component Installation" -Status "Installing ASP.NET" -PercentComplete (2/7*100) #DISM /Online /Enable-Feature /FeatureName:IIS-ASPNET /All /Quiet #Write-Progress -Activity "IIS Component Installation" -Status "Installing ASP.NET 4.5" -PercentComplete (3/7*100) #DISM /Online /Enable-Feature /FeatureName:IIS-ASPNET45 /All /Quiet #Write-Progress -Activity "IIS Component Installation" -Status "Installing web sockets" -PercentComplete (4/7*100) #DISM /Online /Enable-Feature /FeatureName:IIS-WebSockets /All /Quiet Write-Progress -Activity "IIS Component Installation" -Status "Installing IIS management tools" -PercentComplete (5/7*100) DISM /Online /Enable-Feature /FeatureName:IIS-ManagementConsole /All /Quiet #Write-Progress -Activity "IIS Component Installation" -Status "Installing web filtering" -PercentComplete (6/7*100) #DISM /Online /Enable-Feature /FeatureName:IIS-RequestFiltering /All /Quiet Write-Progress -Activity "IIS Component Installation" -Status "IIS setup completed" -PercentComplete (7/7*100) -Completed Start-Sleep 2 } Clear-Host ### Create IIS Site ## [System.IO.Directory]::CreateDirectory($SitePath) if ((Get-IISAppPool -Name $AppPoolName) -eq $null) { New-WebAppPool -Name $AppPoolName Set-ItemProperty -Path "IIS:\AppPools\$AppPoolName" -name processModel.identityType -Value 4 Set-ItemProperty -Path "IIS:\AppPools\$AppPoolName" -name processModel.loadUserProfile -Value $true } if ((Get-Website -Name $SiteName) -eq $null) { New-Website -Name $SiteName -PhysicalPath $SitePath -HostHeader $BindingHostname -ApplicationPool $AppPoolName } Wrap-Host Wrap-Host "This will DELETE ALL FILES in the selected website and install Remotely Server. If this is not your intention, close this window now and create a new website where Remotely Server will be installed." -ForegroundColor Red Wrap-Host Do-Pause # Stop site. Clear-Host Wrap-Host Wrap-Host "Stopping website..." -ForegroundColor Green Stop-Website -Name $SiteName ### File Cleanup ### Wrap-Host Wrap-Host "Cleaning up existing files..." -ForegroundColor Green $Success = $false while ($Success -eq $false) { try { Get-ChildItem -Path "$SitePath" -Recurse | Remove-Item -Force -Recurse $Success = $true } catch { Start-Sleep -Seconds 1 } } ### Download Server Package ### try { if ((Test-Path -Path "$env:TEMP\Remotely_Server_Win-x64.zip")){ Remove-Item -Path "$env:TEMP\Remotely_Server_Win-x64.zip" -Force } Wrap-Host "Downloading server package..." $ProgressPreference = "SilentlyContinue" Invoke-WebRequest -Uri "https://github.com/Jay-Rad/Remotely/releases/latest/download/Remotely_Server_Win-x64.zip" -OutFile "$env:TEMP\Remotely_Server_Win-x64.zip" $ProgressPreference = "Continue" Wrap-Host "Extracting server files..." [System.Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem") | Out-Null [System.IO.Compression.ZipFile]::ExtractToDirectory("$env:TEMP\Remotely_Server_Win-x64.zip", $SitePath) } catch { Wrap-Host Wrap-Host "Error: Unable to download or extract client files." -ForegroundColor Red Do-Pause return } ### Set ACL on website folders and files ### Wrap-Host Wrap-Host "Setting ACLs..." -ForegroundColor Green $Acl = Get-Acl -Path $SitePath $Rule = New-Object System.Security.AccessControl.FileSystemAccessRule("BUILTIN\IIS_IUSRS", "Modify", "ContainerInherit,ObjectInherit", "None", "Allow") $Acl.AddAccessRule($Rule) $Acl.SetOwner((New-Object System.Security.Principal.NTAccount("Administrators"))) Set-Acl -Path $SitePath -AclObject $Acl Get-ChildItem -Path $SitePath -Recurse | ForEach-Object { Set-Acl -Path $_.FullName -AclObject $Acl } ### Firewall Rules ### Wrap-Host Wrap-Host "Checking firewall rules for HTTP/HTTPS..." -ForegroundColor Green try { Enable-NetFirewallRule -Name "IIS-WebServerRole-HTTP-In-TCP" Enable-NetFirewallRule -Name "IIS-WebServerRole-HTTPS-In-TCP" if ((Get-NetFirewallRule -Name "IIS-WebServerRole-HTTP-In-TCP").Enabled -like "False" -or (Get-NetFirewallRule -Name "IIS-WebServerRole-HTTP-In-TCP").Enabled -like "False") { $FirewallSet = $false } else { $FirewallSet = $true } } catch { $FirewallSet = $false } # Start website. Start-Website -Name $SiteName ### SSL certificate installation. ### if ($WacsPath -ne $null -and (Test-Path -Path $WacsPath)) { &"$WacsPath" --target iis --siteid (Get-Website -Name $SiteName).ID --installation iis --emailaddress $EmailAddress --accepttos } Wrap-Host Wrap-Host Wrap-Host Wrap-Host "**********************************" Wrap-Host " Server setup complete!" -ForegroundColor Green Wrap-Host "**********************************" Wrap-Host Wrap-Host "If a path to Win-Acme exe path (WacsPath) wasn't provided, SSL/TLS needs to be set up in IIS. I recommend checking out Let's Encrypt for free, automated SSL certificates." -ForegroundColor Green if ($RebootRequired) { Wrap-Host Wrap-Host "A reboot is required for the new IIS components to work properly. Please reboot your computer at your earliest convenience." -ForegroundColor Red } if ($FirewallSet -eq $false) { Wrap-Host Wrap-Host "Firewall rules were not properly set. Please ensure that ports 80 (HTTP) and 443 (HTTPS) are open. Windows Firewall has predefined rules for these called ""World Wide Web Services (HTTP(S) Traffic-In)""." -ForegroundColor Red } if ($CopyErrors) { Wrap-Host Wrap-Host "There were errors copying some of the server files. Please try deleting all files in the website directory and trying again." -ForegroundColor Red } Wrap-Host Do-Pause