컴퓨터/기타

[WinSCP + PowerShell] Host의 SSH Key 구하기

k1asd1 2024. 6. 26. 11:59
728x90
반응형

업무상 WinSCP를 가끔 사용하는데 WinSCP에서 제공하는 스크립트를 단독으로 실행하려니 Host의 SSH Key가 필요하다고 합니다.

 

공식 홈페이지에서 Host의 SSH Key와 관련된 예제를 찾을 수 있었고 기록으로 남기고자 합니다.

 

 

공식 홈페이지에서 제공하는 WinSCP 6.3.3 Portable을 기준으로 작성되었습니다.

 

스크립트와 WinSCP 실행 파일이 같이 있는 경우 홈페이지의 스크립트를 그대로 사용하면 되고

 

스크립트를 따로 보관하는 경우 절대 경로 또는 상대 경로를 지정하면 됩니다.



* 공식 홈페이지의 SSH Key 구하는 예제

- https://winscp.net/eng/docs/library_example_known_hosts#google_vignette

 

Implementing SSH host key cache (known hosts) :: WinSCP

Implementing SSH host key cache (known hosts) The following example shows how to implement a custom SSH host key cache, similar to the .ssh/known_hosts file of OpenSSH suite, using WinSCP .NET assembly. If you do not need our own cache storage, you can ins

winscp.net

 


※ 파일 경로

* WinSCP 경로

- D:\WinSCP-6.3.3-Portable

 

* WinSCP .NET Assembly

- D:\WinSCP-6.3.3-Portable\WinSCPnet.dll

 

* 스크립트 (임의 이름 지정)

- D:\WinSCP-6.3.3-Portable\Extensions\GetSSHHostKey.ps1

 

 

* 스크립트 추가 및 수정

- 추가
$path = (Split-Path $PSScriptRoot) + "\"


- 원본
$KnownHostsFile = "KnownHosts.xml"
- 수정
$KnownHostsFile = $PSScriptRoot + "\" + "KnownHosts.xml"


- 원본
Add-Type -Path "WinSCPnet.dll"
- 수정
Add-Type -Path (Join-Path $path "WinSCPnet.dll")


- 수정
: # Setup session options의 HostName, UserName, Password는 환경에 맞게 수정

 

 

* 수정된 전체 스크립트

$path = (Split-Path $PSScriptRoot) + "\"
$KnownHostsFile = $PSScriptRoot + "\" + "KnownHosts.xml"
$SshPortNumber = 22

try
{
    # Load WinSCP .NET assembly
    # Add-Type -Path "WinSCPnet.dll"
    Add-Type -Path (Join-Path $path "WinSCPnet.dll")
 
    # Setup session options
    $sessionOptions = New-Object WinSCP.SessionOptions -Property @{
        Protocol = [WinSCP.Protocol]::Sftp
        HostName = "example.com"
        UserName = "user"
        Password = "mypassword"
    }
 
    # Cache key is hostname:portnumber
    if ($sessionOptions.PortNumber -ne 0)
    {
        $portNumber = $sessionOptions.PortNumber
    }
    else
    {
        $portNumber = $SshPortNumber
    }
    $sessionKey = ("{0}:{1}" -f $sessionOptions.HostName, $portNumber)
 
    # Load known hosts (if any)
    if (Test-Path $KnownHostsFile)
    {
        [xml]$knownHosts = Get-Content $KnownHostsFile
    }
    else
    {
        $knownHosts = New-Object System.XML.XmlDocument
        $knownHosts.AppendChild($knownHosts.CreateElement("KnownHosts")) | Out-Null
    }
 
    # Lookup host key for this session 
    $fingerprint =
        $knownHosts.DocumentElement |
        Select-Xml -XPath "KnownHost[@host='$sessionKey']/@fingerprint"
 
    if ($fingerprint)
    {
        Write-Host "Connecting to a known host"
    }
    else
    {
        # Host is not known yet. Scan its host key and let the user decide.
        $session = New-Object WinSCP.Session
        try
        {
            $fingerprint = $session.ScanFingerprint($sessionOptions, "SHA-256")
        }
        finally
        {
            $session.Dispose()
        }
 
        Write-Host -NoNewline (
            "Continue connecting to an unknown server and add its host key to a cache?`n" +
            "The server's host key was not found in the cache.`n" + 
            "You have no guarantee that the server is the computer you think it is.`n" +
            "`n" +
            "The server's key fingerprint is:`n" +
            $fingerprint + "`n" +
            "`n" +
            "If you trust this host, press Y. To abandon the connection, press N. ")
 
        do
        {
            $key = [char]::ToUpperInvariant([System.Console]::ReadKey($True).KeyChar)
            if ($key -eq "N")
            {
                Write-Host($key)
                exit 2
            }
        }
        while ($key -ne "Y")
 
        Write-Host($key)
 
        # Cache the host key
        $knownHost = $knownHosts.CreateElement("KnownHost")
        $knownHosts.DocumentElement.AppendChild($knownHost) | Out-Null
        $knownHost.SetAttribute("host", $sessionKey)
        $knownHost.SetAttribute("fingerprint", $fingerprint)
 
        $knownHosts.Save($KnownHostsFile)
    }
 
    # Now we have the fingerprint
    $sessionOptions.SshHostKeyFingerprint = $fingerprint
 
    $session = New-Object WinSCP.Session
 
    try
    {
        # Connect
        $session.Open($sessionOptions)
 
        # Your code
    }
    finally
    {
        # Disconnect, clean up
        $session.Dispose()
    }
}
catch
{
    Write-Host "Error: $($_.Exception.Message)"
    exit 1
}

 

 

* 실행 및 결과

- 실행 명령어

powershell.exe -ExecutionPolicy Bypass -File "D:\util\WinSCP-6.3.3-Portable\Extensions\GetSSHHostKey.ps1"

실행 결과

- 스크립트 실행 시 'ssh' 로 시작하는 문자열을 확인할 수 있습니다.

- 'Y' 입력 시 스크립트와 같은 경로에 변수로 지정했던 'KnownHosts.xml'이 정상적으로 생성되었습니다.


이상입니다.

728x90
반응형