<# .SYNOPSIS Installs and configures OpenSSH Server on a Windows system, creates a local group and user account, and sets up SFTP access with a custom port and root folder. .DESCRIPTION This script automates the process of installing and configuring OpenSSH Server on a Windows system, creating a local group and user account, and setting up SFTP access with a custom port and root folder. It also configures the firewall rules, sets up the SFTP root folder, and updates the sshd_config file accordingly. .PARAMETER Force Optional parameter to force the installation and configuration of OpenSSH Server, even if it's already installed. .NOTES This script is intended for use in a test or production environment. Make sure to test the script in a non-production environment before running it in production. Author: W. Manurat DISCLAIMER: Use scripts at your own risk, if there is anything I can help you with I will try but I do not take responsibility for the way that anyone else uses my scripts. Sharing is caring. Share your knowledge with the world so that everybody can learn from it. .LINK The latest version can Always be found on my GIT page on the link below: https://git.dcomputers.nl/Dcomputers/PowershellScripts #> #Parameters param( [Parameter(Mandatory=$false)] [Bool]$Force ) #region Global script settings and variables #General $Version = "v1.0" $logfilelocation = "$($MyInvocation.MyCommand.Path | Split-Path -Parent)\Logs" $logfilename = "$(Get-Date -Format yyyyMMddHHmmss)-Install-SFTP-Server.log" #User Inputs $customPort = Read-Host "Please enter the local port to be used for OpenSSH" $groupName = Read-host "Enter the groupname" $userName = Read-host "Enter the username for the user" $password = Read-host "Enter the password for the user" -AsSecureString $sshFilesPath = Read-host "Enter the full path to the SFTP root folder" #endregion #region prerequisites check #Create log directory if not present and initiate logfile if (!(test-path $logfilelocation)) {mkdir $logfilelocation} Start-Transcript -path "$logfilelocation\$logfilename" -Append -Verbose #Validate user input if ($customPort -match '^\d+$') { $portNumber = [long]$customPort $check = $portNumber -ge 1 -and $portNumber -le 65535 } else { $check = $false } if (($null -eq $customPort) -or (!($check))){ Write-Host "ERROR: The specified custom port does not range between 1 - 65535." Write-Host "ERROR: Rerun script with the correct parameter" Stop-Transcript Pause exit 1 } #Check and install required roles $Roles = @("OpenSSH.Client~~~~0.0.1.0","OpenSSH.Server~~~~0.0.1.0") if (!($Force)){ if (!(Get-WindowsCapability -Online | Where-Object {$_.Name -in $Roles -and $_.State -ne 'Installed'})){ Write-Host "ERROR: All roles are already installed." Write-Host "Rerun Script with -Force to force installation and configuration" Stop-Transcript Pause exit 1 } } foreach ($role in $Roles) { $check = Get-WindowsCapability -Online | Where-Object { $_.Name -eq "$role" } | Select-Object -ExpandProperty State if ($check -ne "Installed"){ Write-Host "The role $role is not installed, installing it now" Add-WindowsCapability -Online -Name $role } else { Write-Host "INFO: $role is already installed skipping installation..." } } #Start Service $service = "sshd" Set-Service -Name $service -StartupType 'Automatic' Write-Host "INFO: Service Startup type changed to 'Automatic'" Start-Service -Name $service Write-Host "INFO: Service started" #endregion #region performing stufffs #Configure firewall rules #Disable default FW rule if (Get-NetFirewallRule -Name "*SSH*" -ErrorAction SilentlyContinue) { Disable-NetFirewallRule -Name "*SSH*" Write-Host "INFO: Default Firewall Rule 'OpenSSH-Server-In-TCP' has been disabled." } else { Write-Host "INFO: Default Firewall Rule 'OpenSSH-Server-In-TCP' does not exist." } #Create custom FW rule # Check if a firewall rule with the same name already exists if (!(Get-NetFirewallRule -Name "OpenSSH-Server-CustomPort-$customPort" -ErrorAction SilentlyContinue)) { # Create a new firewall rule for OpenSSH with the custom port New-NetFirewallRule -Name "OpenSSH-Server-CustomPort-$customPort" ` -DisplayName "OpenSSH Server (sshd) Custom Port $customPort" ` -Enabled True ` -Direction Inbound ` -Protocol TCP ` -Action Allow ` -LocalPort $customPort Write-Host "INFO: New Firewall Rule 'OpenSSH-Server-CustomPort-$customPort' has been created and enabled." } else { Write-Host "WARNING: Firewall Rule 'OpenSSH-Server-CustomPort-$customPort' already exists." if ($Force){ Get-NetFirewallRule -Name "OpenSSH-Server-CustomPort-$customPort" | Remove-NetFirewallRule -Confirm $false Write-Host "INFO: Old (duplicate) custom rule is removed" New-NetFirewallRule -Name "OpenSSH-Server-CustomPort-$customPort" ` -DisplayName "OpenSSH Server (sshd) Custom Port $customPort" ` -Enabled True ` -Direction Inbound ` -Protocol TCP ` -Action Allow ` -LocalPort $customPort Write-Host "INFO: New Firewall Rule 'OpenSSH-Server-CustomPort-$customPort' has been created and enabled." } } #Create Group & User #Create Group if not exists if (Get-LocalGroup -Name $groupName -ErrorAction SilentlyContinue) { Write-Host "WARNING: The group $groupName already exists." } else { New-LocalGroup -Name $groupName -Description "Group for SFTP access users" Write-Host "INFO: Group $groupName has been created." } #create User and assign custom SFTP group if (Get-LocalUser -Name $userName -ErrorAction SilentlyContinue) { Write-Host "WARNING: The user $userName already exists." $groupMembers = Get-LocalGroupMember -Group "$groupName" | Select-Object -ExpandProperty name if (!($groupMembers -like "*$userName*")){ Write-Host "WARNING: The user is not part of the $groupName group. Adding user to the group." Add-LocalGroupMember -Group $groupName -Member $userName Write-Host "INFO: User $userName has been created and added to the group $groupName." } } else { New-LocalUser -Name $userName -Password $password -Description "User with SFTP access" -AccountNeverExpires -PasswordNeverExpires Add-LocalGroupMember -Group $groupName -Member $userName Write-Host "INFO: User $userName has been created and added to the group $groupName." } #Create SFTP Root folder if (!(Test-Path "$sshFilesPath")) { New-Item -Path "$sshFilesPath" -ItemType Directory Write-Host "INFO: The SFTP root folder has been created at: $sshFilesPath." } else { Write-Host "WARNING: The SFTP root folder already exists at: $sshFilesPath." } #Configure sshd_config # Read the current contents of the sshd_config file $sshdConfig = Get-Content (Join-Path $env:ProgramData "ssh\sshd_config") # Change the default port using the value entered by the user $sshdConfig = $sshdConfig -replace '^(#?Port\s+).*$', "Port $customPort" # Add the SFTP configuration block for the group $groupname $sftpConfig = @" # SFTP configuration for group $groupname Match Group $groupname ForceCommand internal-sftp ChrootDirectory "$sshFilesPath" AllowTcpForwarding no X11Forwarding no "@ # Check if the SFTP configuration is already present if (-Not ($sshdConfig -join "`n" -match "Match Group $groupname")) { # Append SFTP configuration with a newline for separation $sshdConfig += "`n" + $sftpConfig Write-Host "INFO: SFTP configuration has been added to the sshd_config file." } else { Write-Host "WARNING: SFTP configuration is already present in the sshd_config file." } # Write the modified content back to the sshd_config file $sshdConfig | Set-Content -Path (Join-Path $env:ProgramData "ssh\sshd_config") -Force Write-Host "INFO: The 'sshd_config' file has been updated successfully." # Restart the SSH service to apply changes Stop-Service -Name "sshd" Start-Service -Name "sshd" Write-Host "INFO: OpenSSH service has been restarted to apply the changes." #endregion Stop-Transcript pause Exit 0