Setting up a SFTP server on Windows Server
Before we start, check your network connection. If you have no internet connection, you can see last section of this articles to install offline.
PS C:\Windows\system32> Test-Connection www.google.com
Source Destination IPV4Address IPV6Address Bytes Time(ms)
------ ----------- ----------- ----------- ----- --------
COM-TPD-1778 www.google.com 64.233.170.104 32 23
COM-TPD-1778 www.google.com 64.233.170.104 32 22
COM-TPD-1778 www.google.com 64.233.170.104 32 20
COM-TPD-1778 www.google.com 64.233.170.104 32 21
Check Existing OpenSSH Capabilities
First, ensure that OpenSSH is installed on your Windows Server. Open PowerShell as an administrator and run the following command to check the installed capabilities:
Get-WindowsCapability -Online | where Name -like "OpenSSH*"
The output should display the following if OpenSSH is not installed:
Name : OpenSSH.Client~~~~0.0.1.0
State : Installed
Name : OpenSSH.Server~~~~0.0.1.0
State : NotPresent
Install OpenSSH Server
If the OpenSSH Server is not present, you can install it using the following command (Choose one):
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
dism /online /Add-Capability /CapabilityName:OpenSSH.Server~~~~0.0.1.0
Deployment Image Servicing and Management tool
Version: 10.0.22621.2792
Image Version: 10.0.22631.4037
[==========================100.0%==========================]
The operation completed successfully.
Verify that the installation was successful:
Get-WindowsCapability -Online | where Name -like "OpenSSH*"
Name : OpenSSH.Client~~~~0.0.1.0
State : Installed
Name : OpenSSH.Server~~~~0.0.1.0
State : Installed
Start and Configure the SSHD Service
Get current status
Get-Service -Name "sshd"
Status Name DisplayName
------ ---- -----------
Stopped sshd OpenSSH SSH Server
Start the service
Start-Service sshd
WARNING: Waiting for service 'OpenSSH SSH Server (sshd)' to start...
PS C:\Windows\system32> Get-Service -Name "sshd"
Status Name DisplayName
------ ---- -----------
Running sshd OpenSSH SSH Server
Configure SSHD
By default, SSH listens on port 22. To change this, edit the sshd_config
file. Find the current port configuration:
Get-Content "C:\ProgramData\ssh\sshd_config" | findstr Port
#Port 22
#GatewayPorts no
Change the port number by replacing Port 22
with your desired port number in the sshd_config
file. Restart the SSHD service to apply the changes (This is optional):
(Get-Content "C:\ProgramData\ssh\sshd_config").replace("Port 22", "Port <your-new-port>") | Set-Content "C:\ProgramData\ssh\sshd_config" | Restart-Service sshd
You also can edit from notepad
notepad C:\ProgramData\ssh\sshd_config
Restart
Restart-Service -Name sshd
#You can use Command Prompt to restart the sshd service by leveraging the net command:
net stop sshd
net start sshd
Verify Port Listening
Ensure that the port is listening :
Get-NetTCPConnection -LocalPort 22 | select Local*, State,`
@{n="ProcessName";e={(Get-Process -Id $_.OwningProcess).ProcessName}},`
@{n="ProcessPath";e={(Get-Process -Id $_.OwningProcess).Path}} | ft -Auto
LocalAddress LocalPort State ProcessName ProcessPath
------------ --------- ----- ----------- -----------
:: 22 Listen sshd C:\Windows\System32\OpenSSH\sshd.exe
0.0.0.0 22 Listen sshd C:\Windows\System32\OpenSSH\sshd.exe
Create a User for SFTP Access
Create a new local user for SFTP access:
$userName = "sftpuser"
$password = "<your-password>"
New-LocalUser -Name $userName -Password (ConvertTo-SecureString $password -AsPlainText -Force) -FullName "SFTP User" -Description "SFTP Access User"
Name Enabled Description
---- ------- -----------
sftpuser True SFTP Access User
If you need to change the password
# Change the password for the existing user
$newPassword = "<your-new-password>"
Set-LocalUser -Name $userName -Password (ConvertTo-SecureString $newPassword -AsPlainText -Force)
Review All Users
Verify that the sftpuser
is correctly listed:
Get-LocalUser | Select-Object Name, Enabled
Name Enabled
---- -------
Administrator False
DefaultAccount False
Guest False
MUSR_MQADMIN True
sftpuser True
Think True
WDAGUtilityAccount False
Enable or Disable
$userName= "sftpuser"
Disable-LocalUser -Name $UserName
$userName= "sftpuser"
Enable-LocalUser -Name $UserName
Set Up a Directory for SFTP
Create a directory that the user will have access to:
$folderPath = "C:\SFTPFolder"
New-Item -Path $folderPath -ItemType Directory -Force
PS C:\Windows\system32> New-Item -Path $folderPath -ItemType Directory -Force
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 8/26/2024 11:42 AM SFTPFolder
$acl = Get-Acl $folderPath
$permission = "$env:COMPUTERNAME\$userName", "ReadAndExecute", "ContainerInherit, ObjectInherit", "None", "Allow"
$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule $permission
$acl.AddAccessRule($accessRule)
Set-Acl -Path $folderPath -AclObject $acl
Verify User Permissions
Check that the user has the correct permissions:
$folderPath = "C:\SFTPFolder"
$acl = Get-Acl $folderPath
$acl.Access | Select-Object IdentityReference, FileSystemRights, AccessControlType
IdentityReference FileSystemRights AccessControlType
----------------- ---------------- -----------------
COM-TPD-1778\sftpuser ReadAndExecute, Synchronize Allow
BUILTIN\Administrators FullControl Allow
NT AUTHORITY\SYSTEM FullControl Allow
BUILTIN\Users ReadAndExecute, Synchronize Allow
NT AUTHORITY\Authenticated Users Modify, Synchronize Allow
NT AUTHORITY\Authenticated Users -536805376 Allow
Generate Report
$users = Get-LocalUser | Select-Object Name
This command retrieves a list of all local users on the system and selects their Name
property. The result is stored in the $users
variable.
$report = foreach ($user in $users) {
$access = $acl.Access | Where-Object { $_.IdentityReference -like "*$($user.Name)*" }
[PSCustomObject]@{
UserName = $user.Name
Permissions = if ($access) { $access.FileSystemRights -join ", " } else { "No Access" }
}
}
PS C:\Windows\system32> $report
UserName Permissions
-------- -----------
Administrator FullControl
DefaultAccount No Access
Guest No Access
MUSR_MQADMIN No Access
sftpuser ReadAndExecute, Synchronize
Think No Access
WDAGUtilityAccount No Access
Accsess SFTP
Access your SFTP server from CLI or Toolkit like WinSCP
Allow SSH Through Windows Firewall
Ensure that the Windows Firewall allows SSH connections:
netsh advfirewall firewall add rule name="OpenSSH Server (sshd)" dir=in action=allow protocol=TCP localport=22
Get-NetFirewallRule | Format-Table -Property Name, DisplayName, Enabled, Direction, Action, Profile | findstr OpenSSH
Install Package Offline
You need to download the Feature On Demand Package, inside the ISO there is file called OpenSSH-Server-Package~31bf3856ad364e35~amd64~~.cab place in folder LanguagesAndOptionalFeatures
Windows 11, version 22H2 Language and Optional Features ISO (Source)
Download the FOD ISO.iso
Windows 10, version 2004 (and later) Features on Demand #1 ISO (Source)
Download the FOD ISO.iso
The command-line syntax to install a FOD CAB file is below:
dism /online /add-package /packagepath:"<where-your-cab-placed>"
dism /online /add-package /packagepath:"C:\Users\danang.priabada\Documents\OpenSSH-Server-Package~31bf3856ad364e35~amd64~~.cab"
Deployment Image Servicing and Management tool
Version: 10.0.22621.2792
Image Version: 10.0.22631.4037
Processing 1 of 1 - Adding package OpenSSH-Server-Package~31bf3856ad364e35~amd64~~10.0.22621.1
[===========================61.0%=== ]
[===========================66.0%====== ]
[===========================67.6%======= ]
[===========================69.3%======== ]
[===========================71.0%========= ]
[===========================71.0%========= ]
[===========================72.6%========== ]
[===========================74.3%=========== ]
[===========================76.0%============ ]
[===========================80.0%=============== ]
[===========================87.0%===================== ]
[===========================98.0%======================= ]
[==========================100.0%==========================]
The operation completed successfully.
Get-WindowsCapability -Online | where Name -like "OpenSSH*"
Name : OpenSSH.Client~~~~0.0.1.0
State : Installed
Name : OpenSSH.Server~~~~0.0.1.0
State : Installed