Windows ServerのSFTP/TFTP稼働確認をPowerShellで行う方法(sshd・ポート22/UDP69・棚卸し対応)

Windows Serverで「SFTP/TFTPが動いているか(有効か)」を確実に確認するには、Server Managerで“役割や機能が入っているか”を見るだけでは足りないことが多いです。PowerShellで実装の種類→サービス→待受ポート→ファイアウォール→ログ→実通信の順に確認すると、環境差に振り回されずに判定できます。

目次

SFTP/TFTPの稼働確認で迷う理由(結論:何の実装を入れているか次第)

SFTPとTFTPは、どちらも「プロトコル名」ですが、Windows Server上で“標準でこのサービスが必ずある”というタイプではありません。とくにSFTPはIISのFTP(Web-Ftp-Server)とは別物で、TFTPは製品(実装)依存になりがちです。したがってPowerShellでは、1つのコマンドで万能に判定するよりも、複数の観点を組み合わせて確認するのが現実的です。

項目SFTPTFTP
何の上で動くかSSH(Secure Shell)上のファイル転送UDPで動く軽量な転送(機能は最小限)
代表ポートTCP 22(変更されることもある)UDP 69(変更されることもある)
Windows Serverでよくある実装OpenSSH Server(sshd)などサードパーティ製TFTPサーバー/機器付属TFTPなど
「役割/機能」で判定できるかOpenSSHはCapability(Windowsの追加機能)で確認できる場合ありWindowsにあるのは主にTFTPクライアント(サーバーは別)
PowerShellでの現実的な確認軸サービス(sshd)/待受(22/TCP)/ログ/実接続サービス・プロセス名/待受(69/UDP)/実転送(tftp)

「有効/稼働」の判定基準を揃える(ここが曖昧だと結論がブレる)

“SFTP/TFTPが有効”と言っても、現場では次の状態が混在します。どれをゴールにするかを先に揃えると、確認手順がズレません。

判定したい状態見るべきポイントPowerShellでの代表アプローチ
機能(実装)が入っているCapability/Windows機能/インストール済みプログラムGet-WindowsCapability / Get-WindowsFeature / サービス探索
サービスが起動しているサービスの状態(Running)Get-Service / Get-CimInstance Win32_Service
ポートが待受しているLISTEN(TCP)/バインド(UDP)Get-NetTCPConnection / Get-NetUDPEndpoint
疎通できるネットワーク経路・FW・ACLTest-NetConnection(SFTP向き)
実際に転送できる認証・権限・パス・サブシステムsftp / tftp を使った実転送(最終確認)
監査・証跡が取れるイベントログ・アプリログGet-WinEvent

最優先:まずはサービス/プロセスで「それっぽい実装」を特定する

「そのサーバーに何が入っているか分からない」状態では、機能名を当てに行くより、サービス名・表示名・プロセス名を広く探索するほうが早いです。ここで“候補”を掴むと、その後の確認が一気に楽になります。

サービス名・表示名で探索(ssh / sftp / tftp)

# サービス名・表示名に ssh / sftp / tftp を含むものを広く探索
Get-Service |
  Where-Object { $_.Name -match 'ssh|sftp|tftp' -or $_.DisplayName -match 'ssh|sftp|tftp' } |
  Sort-Object Name |
  Format-Table Status, Name, DisplayName -AutoSize

# サービス詳細(実行ファイルパスや起動アカウントまで見る)

Get-CimInstance Win32_Service |
Where-Object { $*.Name -match 'ssh|sftp|tftp' -or $*.DisplayName -match 'ssh|sftp|tftp' } |
Select-Object State, Name, DisplayName, StartMode, StartName, PathName |
Sort-Object Name |
Format-Table -AutoSize

プロセス名で探索(稼働実態の把握)

# プロセス名に ssh / sftp / tftp を含むものを探索
Get-Process |
  Where-Object { $_.Name -match 'ssh|sftp|tftp' } |
  Sort-Object Name |
  Format-Table Name, Id, CPU, StartTime -AutoSize

ポイント:SFTPの本命がOpenSSH Serverなら、サービス名はsshdであることが多いです。逆に、IISのFTP(Web-Ftp-Server)が見つかっても、それはFTP/FTPSであってSFTPではありません。

SFTPの稼働確認(OpenSSH Server / sshd を前提に“同等以上”で確認)

SFTPはSSH上で動くため、PowerShellではsshdサービス22/TCPの待受を中心に確認するとブレません。加えて、SFTPサブシステム(sftp-server)が有効か、ログが出ているかまで見れば「動いている」の確度が上がります。

sshdサービスの状態を確認(最短で結論に近い)

# sshd の状態(存在しない場合は未導入 or 別実装の可能性)
Get-Service sshd -ErrorAction SilentlyContinue

# 起動状態を明確に表示

$svc = Get-Service sshd -ErrorAction SilentlyContinue
if ($null -eq $svc) {
'sshd サービスが見つかりません(OpenSSH Server未導入、または別実装の可能性)'
} else {
$svc | Format-List Name, DisplayName, Status, StartType
}

OpenSSH Serverが「Windowsの追加機能」として入っているか確認

Windows Serverのバージョンによっては、OpenSSH ServerがCapabilityとして管理されています。名前の末尾(バージョン文字列)は環境で揺れるため、ワイルドカードで確認するのが安全です。

# OpenSSH Server のインストール状態(Capability)
Get-WindowsCapability -Online |
  Where-Object { $_.Name -like 'OpenSSH.Server*' } |
  Select-Object Name, State

もし「入っているのにsshdがない」場合は、インストールはされていてもサービスが無効化されていたり、何らかの理由で構成が壊れている可能性があります。まずはサービス探索(前述)とイベントログで状況を切り分けます。

待受ポート(22/TCP)を確認(“稼働実態”に近い)

サービスがRunningでも、設定や権限、衝突などで待受できていないことがあります。待受確認は「動いているか」の精度を上げます。

# 22/TCPがLISTENしているか(ローカルサーバー上で確認)
Get-NetTCPConnection -State Listen -LocalPort 22 -ErrorAction SilentlyContinue

# sshd のプロセスIDに紐づく待受だけを確認(ポート変更にも強い)
$sshd = Get-Process sshd -ErrorAction SilentlyContinue
if ($sshd) {
  Get-NetTCPConnection -State Listen -OwningProcess $sshd.Id |
    Select-Object LocalAddress, LocalPort, OwningProcess, State |
    Format-Table -AutoSize
} else {
  'sshd プロセスが見つかりません(サービス停止中、または別実装の可能性)'
}

ファイアウォール(受信規則)の確認(“起動しているのに繋がらない”の典型原因)

Windows Defender Firewallで受信が塞がっていると、サービスが動いていても外からは接続できません。規則名は環境で異なるため、ssh/openssh/22を手掛かりに確認します。

# SSH関連のファイアウォール規則を探索
Get-NetFirewallRule |
  Where-Object { $_.DisplayName -match 'SSH|OpenSSH' -or $_.Group -match 'OpenSSH|SSH' } |
  Select-Object DisplayName, Enabled, Direction, Action, Profile |
  Format-Table -AutoSize

# 22/TCP を対象にしている受信規則(ポートフィルタ)を確認
Get-NetFirewallRule -Direction Inbound -Enabled True |
  Get-NetFirewallPortFilter |
  Where-Object { $_.Protocol -eq 'TCP' -and $_.LocalPort -eq '22' } |
  Select-Object LocalPort, Protocol, @{n='RuleName';e={$_.InstanceID}} |
  Format-Table -AutoSize

運用上は「ドメインプロファイルだけ許可」「特定サブネットだけ許可」など、スコープで絞るのが定石です。接続試験前に、意図したプロファイル(Domain/Private/Public)で許可されているかも確認しておくと、手戻りが減ります。

SFTPサブシステムが有効か(sshd_configの確認)

SFTPはSSHの上で動きますが、sshd側でSFTPサブシステムが無効化されていると、SSHは通るのにSFTPだけ失敗するケースが起きます。WindowsのOpenSSHでは、設定ファイルが次のパスにあることが多いです。

  • C:\ProgramData\ssh\sshd_config
  • 実体のSFTPサーバー:C:\Windows\System32\OpenSSH\sftp-server.exe(環境により異なる場合あり)
# sshd_config の存在確認
Test-Path 'C:\ProgramData\ssh\sshd_config'

# Subsystem 設定(SFTP)を抽出
Select-String -Path 'C:\ProgramData\ssh\sshd_config' -Pattern '^\s*Subsystem\s+sftp' -ErrorAction SilentlyContinue

# sftp-server.exe の存在確認(OpenSSHの配置が一般的な場所の場合)
Test-Path 'C:\Windows\System32\OpenSSH\sftp-server.exe'

実務の落とし穴:「SSHでログインはできるのにSFTPだけできない」場合、Subsystem設定や、SFTP用の許可(ユーザーのローカル権限・NTFS権限・Chroot相当の制約など)が原因になりやすいです。まずはログを見て、認証失敗なのか、サブシステム起動失敗なのかを切り分けます。

イベントログで接続試行の痕跡を見る(監査・切り分けに強い)

GUIでイベントビューアを見る代わりに、PowerShellで直近ログを引けるようにしておくと、遠隔作業や棚卸しで強力です。ログ名は環境で差がありますが、OpenSSHの運用ログが用意されている場合はそこから辿れます。

# OpenSSH運用ログ(存在する場合)を直近から取得
Get-WinEvent -LogName 'OpenSSH/Operational' -MaxEvents 50 -ErrorAction SilentlyContinue |
  Select-Object TimeCreated, Id, LevelDisplayName, Message |
  Format-Table -AutoSize

もしログが見つからない/出ない場合でも、サービスの状態・待受ポート・ファイアウォール・設定ファイルの整合性を見れば、十分に切り分け可能です。

疎通確認(クライアント側から“TCP 22が開いているか”)

SFTPの入口はSSHなので、まずは22/TCPに到達できるかを確認します。これは、Server Managerでは見えない「ネットワーク越しの現実」を掴むのに有効です。

# クライアント側(別端末)から:TCP 22 が通るか
Test-NetConnection -ComputerName <サーバー名またはIP> -Port 22

さらに踏み込むなら、実際にSFTPで接続・転送して「SFTPとして動いている」を確定させます(鍵やアカウントが必要)。WindowsにOpenSSHクライアントがある環境なら、次のように確認できます。

# 例:SFTPクライアントで接続(対話)
sftp user@<サーバー名またはIP>

# OpenSSHクライアントが入っているか(任意)
Get-WindowsCapability -Online |
  Where-Object { $_.Name -like 'OpenSSH.Client*' } |
  Select-Object Name, State

TFTPの稼働確認(“Windows標準サーバー”と決めつけないのがコツ)

TFTPは「PXE起動」「機器設定のバックアップ」などで今も使われますが、Windows Server上では標準でTFTPサーバーが常に提供されるわけではありません。まずはTFTPクライアントTFTPサーバーを分けて考えると、確認が一気に整理できます。

混同しやすいポイント実態確認の方向性
TFTPが「Windowsの機能」にある多くの場合それはTFTPクライアント(送受信ツール)Get-WindowsFeature / Get-WindowsCapability で「クライアント有無」を確認
TFTPが動いているかTFTPサーバー実装が必要(製品依存)サービス/プロセス/UDP待受(69)/実転送で確認
UDP 69が空いていればOKTFTPは転送時に動的ポートへ移る実装も多い実転送(GET/PUT)で最終確認し、FW要件も確認

サーバー側:UDP 69 の待受を確認(存在すれば強い手掛かり)

# UDP 69 で待受しているエンドポイントを確認
$udp69 = Get-NetUDPEndpoint -LocalPort 69 -ErrorAction SilentlyContinue
$udp69

# OwningProcess からプロセス名を引く(実装特定に役立つ)

if ($udp69) {
$udp69 |
Select-Object LocalAddress, LocalPort, OwningProcess,
@{n='ProcessName';e={(Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).Name}} |
Format-Table -AutoSize
} else {
'UDP 69 の待受が見つかりません(別ポート運用、未起動、未導入の可能性)'
}

ここで何も出ない場合でも、TFTPが別ポートで動いている設計や、サービスが停止中の可能性があります。次はサービス/プロセス探索で当たりを付けます。

サービス/プロセス探索(TFTPは実装ごとに名前が違う)

# サービス名・表示名に tftp を含むものを探索
Get-Service |
  Where-Object { $_.Name -match 'tftp' -or $_.DisplayName -match 'tftp' } |
  Format-Table Status, Name, DisplayName -AutoSize

# サービスの実体(PathName)まで見る

Get-CimInstance Win32_Service |
Where-Object { $*.Name -match 'tftp' -or $*.DisplayName -match 'tftp' } |
Select-Object State, Name, DisplayName, StartMode, PathName |
Format-Table -AutoSize

# プロセス名に tftp を含むものを探索

Get-Process |
Where-Object { $_.Name -match 'tftp' } |
Format-Table Name, Id, CPU, StartTime -AutoSize

サードパーティ製の場合、表示名にTFTPが入らないこともあります。その場合は「UDP 69 のOwningProcess」や、インストール済みアプリ一覧、サービス一覧の“パス(PathName)”から推測するほうが確実です。

Windows機能として確認できるのは主に「TFTPクライアント」

Server Managerで見える「TFTP Client」は、基本的にクライアント機能です。棚卸しでは「TFTPで検証できる端末か」を判断する材料になります。

# Windows Server の機能(Feature)としての TFTP クライアント(環境により名称が異なる場合あり)
Get-WindowsFeature -Name TFTP-Client -ErrorAction SilentlyContinue |
  Select-Object Name, DisplayName, Installed

もし上記が取れない環境では、Capabilityとして提供されているケースもあるため、次のように広く検索します。

# Capability 側にあるケースに備え、tftp を含むCapabilityを広く探索
Get-WindowsCapability -Online |
  Where-Object { $_.Name -match 'tftp' } |
  Select-Object Name, State

実通信で確認する(TFTPは“実転送”が最終的に一番確実)

TFTPはUDPで、単純なポート疎通だけでは判定しにくいです。可能なら、実際にGET/PUTをして成功するかで確認します。TFTPクライアントが利用できる場合は、次のように検証できます(TFTPサーバー側の許可・対象ファイル・ルートディレクトリ設定が必要です)。

# 例:tftp.exe を使って GET(外部コマンド。環境によりオプションは差が出ます)
# -i はバイナリ転送指定として使われることが多い例です
tftp -i <TFTPサーバー> GET <取得したいファイル名>

# PowerShell内で実行して結果を把握したい場合の例(出力が簡素なため、成功/失敗は終了コードやファイル有無で判定)
$server = '<TFTPサーバー>'
$file   = 'test.txt'
$tgt    = Join-Path $PWD $file

# 事前に同名ファイルがあると判定が紛れるので削除
Remove-Item $tgt -ErrorAction SilentlyContinue

# 実行
& tftp -i $server GET $file

# 成否判定(簡易)
if (Test-Path $tgt) {
  "GET成功($tgt を取得)"
} else {
  "GET失敗(ファイルが作成されない。FW/許可/パス/ルート設定などを確認)"
}

TFTPの現場あるある:UDP 69 を開けても、転送フェーズで動的ポートを使う実装だと途中で止まります。疎通確認は「UDP 69待受」+「実転送」でセットにしておくと、原因切り分けが速くなります。

TFTPを運用するなら押さえたいセキュリティ注意点

  • TFTPは認証や暗号化が基本的にありません。置くネットワーク(隔離・ACL・IP制限)を前提にします。
  • ファイアウォールは「全開放」ではなく、送受信元の範囲を絞ります(機器の管理セグメントだけ等)。
  • 監査が必要な環境では、TFTPの利用ログが取れる実装か、代替(SFTP/HTTPS等)へ寄せることも検討します。

Server Manager相当以上:チェック結果を“表”で出して棚卸しする(複数台にも対応)

Server Managerで1台ずつ画面確認する代わりに、PowerShellで「機能」「サービス」「待受」「FW」をまとめて収集すると、棚卸しや監査が一気に楽になります。ここでは、SFTP(sshd)とTFTP(UDP 69)の“現実的な判定材料”を一括で取る例を紹介します。

収集項目目的主なコマンド
OpenSSH Serverの導入状態実装が入っているかGet-WindowsCapability
sshdサービス状態SFTPの土台が起動しているかGet-Service sshd
sshdの待受ポート実際に受け付けているかGet-NetTCPConnection
TCP 22の受信FW外から繋がる設計かGet-NetFirewallRule / Get-NetFirewallPortFilter
UDP 69待受TFTPサーバー候補の有無Get-NetUDPEndpoint
TFTP関連サービス探索製品依存の実装特定Get-CimInstance Win32_Service

単体サーバー用:ローカルで結果をまとめて出す例

# SFTP/TFTP 棚卸し(ローカル実行想定)
$report = [pscustomobject]@{
  ComputerName = $env:COMPUTERNAME

OpenSSH_Server_Capability = (Get-WindowsCapability -Online -ErrorAction SilentlyContinue |
Where-Object { $_.Name -like 'OpenSSH.Server*' } |
Select-Object -First 1 -ExpandProperty State)

sshd_ServiceStatus = (Get-Service sshd -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Status)

sshd_ListenPorts = (
$p = Get-Process sshd -ErrorAction SilentlyContinue
if ($p) {
(Get-NetTCPConnection -State Listen -OwningProcess $p.Id -ErrorAction SilentlyContinue |
Sort-Object LocalPort |
Select-Object -ExpandProperty LocalPort) -join ','
} else {
$null
}
)

TCP22_Listen = [bool](Get-NetTCPConnection -State Listen -LocalPort 22 -ErrorAction SilentlyContinue)

UDP69_EndpointCount = (
(Get-NetUDPEndpoint -LocalPort 69 -ErrorAction SilentlyContinue | Measure-Object).Count
)
}

$report | Format-List

複数台向け:Invoke-Commandで一括収集する例(WinRMが有効な前提)

サーバー一覧(例:servers.txt)を用意して、リモートで同じ収集を走らせます。結果はCSVに落とせるため、監査・台帳にも転用しやすくなります。

# servers.txt にサーバー名を1行1台で記載しておく想定
$servers = Get-Content .\servers.txt

$script = {
  $openSshState = (Get-WindowsCapability -Online -ErrorAction SilentlyContinue |
    Where-Object { $_.Name -like 'OpenSSH.Server*' } |
    Select-Object -First 1 -ExpandProperty State)

  $sshdSvc = Get-Service sshd -ErrorAction SilentlyContinue
  $sshdProc = Get-Process sshd -ErrorAction SilentlyContinue

  $sshdPorts = $null
  if ($sshdProc) {
    $sshdPorts = (Get-NetTCPConnection -State Listen -OwningProcess $sshdProc.Id -ErrorAction SilentlyContinue |
      Sort-Object LocalPort |
      Select-Object -ExpandProperty LocalPort) -join ','
  }

  $tcp22Listen = [bool](Get-NetTCPConnection -State Listen -LocalPort 22 -ErrorAction SilentlyContinue)

  $udp69 = Get-NetUDPEndpoint -LocalPort 69 -ErrorAction SilentlyContinue
  $udp69Count = ($udp69 | Measure-Object).Count
  $udp69ProcNames = $null
  if ($udp69) {
    $udp69ProcNames = ($udp69 |
      Select-Object -ExpandProperty OwningProcess -Unique |
      ForEach-Object { (Get-Process -Id $_ -ErrorAction SilentlyContinue).Name } |
      Where-Object { $_ } |
      Sort-Object -Unique) -join ','
  }

  [pscustomobject]@{
    ComputerName                = $env:COMPUTERNAME
    OpenSSH_Server_Capability   = $openSshState
    sshd_ServiceStatus          = $sshdSvc.Status
    sshd_ListenPorts            = $sshdPorts
    TCP22_Listen                = $tcp22Listen
    UDP69_EndpointCount         = $udp69Count
    UDP69_OwningProcessNames    = $udp69ProcNames
  }
}

$result = Invoke-Command -ComputerName $servers -ScriptBlock $script -ErrorAction Continue

# 画面確認
$result | Sort-Object ComputerName | Format-Table -AutoSize

# 台帳化(例)
$result | Export-Csv .\sftp_tftp_inventory.csv -NoTypeInformation -Encoding UTF8

この形にしておくと、「sshdはRunningだがTCP22がListenしていない」「UDP69が1件だけ出ていてプロセス名が特定できた」など、GUIより早く原因に近づけます。

よくある判定ミスと、最短での切り分け

「IISのFTPを入れたからSFTPも動くはず」

誤りです。IISのWeb-Ftp-ServerはFTP/FTPSであり、SFTPではありません。SFTPを確認したいなら、sshd(OpenSSH Server)の状態と待受を見ます。

「サービスは起動しているのに繋がらない」

  • サーバー側:Get-NetTCPConnection -LocalPort 22で待受があるか
  • サーバー側:受信FW(22/TCP)が許可されているか
  • クライアント側:Test-NetConnection -Port 22で到達できるか

この3点を揃えると、ネットワーク要因なのか、サービス要因なのかを短時間で切り分けできます。

「TFTPはUDP69が開いているのに転送できない」

  • サーバー側:UDP 69の待受(Get-NetUDPEndpoint)
  • 実装の仕様:転送時に動的ポートを使うか(FW要件が変わる)
  • サーバー設定:ルートディレクトリ/GET許可/PUT許可/読み書き権限

TFTPは「ポートが開いている=転送できる」とは限りません。実運用で必要なら、必ず実転送で最終確認しておくのが安全です。

まとめ:PowerShellなら「実装依存」を吸収して、確実に“動いている”を判定できる

  • SFTPはSSH実装(例:OpenSSH Server/sshd)が前提。確認はsshdサービス+待受(22/TCP)+FW+ログ+実接続が王道。
  • TFTPはWindows標準の“サーバー機能”としては限定的で、実装依存になりやすい。確認はサービス/プロセス探索+UDP待受(69)+実転送が確実。
  • 棚卸しや監査は、Invoke-Commandで一括収集→表やCSV化すると、Server Managerより速く再現性も高い。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次