tech.guitarrapc.cóm

Technical updates

PowerShellでTeraTerm接続を自動化してみる

絶賛AWSしてます。 AWSへの接続はsshです。 PowerShellで繋げって?teraterm先生があるので、今はいいかなー (白目 と、ここでteratermを使っていて困るのが、接続の自動化がされず毎回ユーザー名や秘密鍵の選択をさせられることです。 インフラ担当としては、いい加減にしてくださいとなるわけです。 今回、TeratermとPowerShellを連携かして、なるべく自動化してみたいと思います。

Teratermの自動接続

Teratermには、引数でパラメーターを受ける機能があります。 そう、マクロなんて書かなくてもいいのです。 ((
Tera Term Pro コマンドライン
今回は、公開鍵での接続とします。 今時、パスワード認証……ないですよね。

必要な情報

基本AWSのAMIインスタンスに接続なので、ユーザー名は固定なんですが……まぁ一応! 必要な情報は以下です。
  • Teraterm実行ファイルパス(ttermpro.exe)
  • 接続先host
  • 接続先Port
  • sshタイプ
  • 認証タイプ
  • ユーザー名
  • 秘密鍵パス
ようは、以下の形でショートカットを作成すると接続できます。
"C:\Program Files (x86)\teraterm\ttermpro.exe" 192.168.0.100:22 /ssh2 /auth=publickey /user=user /keyfile=D:\key.rsa

追加実装

  1. 一度入力した内容は、jsonでファイル保持します。 今回の場合は、tterapro.exeと秘密鍵パスと接続先hostです。
  2. CUIではなくXamlでGUIライクに

Gitコード公開

GitHubで公開しています。 Xaml (GUI) バージョン:
https://github.com/guitarrapc/PowerShellUtil/blob/master/TeraTermConnection/teraterm_xaml.ps1
CUIバージョン:
https://github.com/guitarrapc/PowerShellUtil/blob/master/TeraTermConnection/Enter-Teraterm.ps1

コード公開

「ファイルを開く」のダイアログをだすためのfunctionを定義します。
function Get-File{

    [CmdletBinding(
        SupportsShouldProcess = $false,
        ConfirmImpact = "none"
    )]

    param
    (
    [Parameter(
    Position = 0
    )]
    [ValidateNotNullOrEmpty()]
    [string]
    $Message,

	[Parameter(
    Position = 1
    )]
    [ValidateNotNullOrEmpty()]
    [string]
    $Extention

	)

    begin
    {
		[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") > $null
        $Dialog = New-Object System.Windows.Forms.OpenFileDialog
    }

    process
    {
        $Dialog.Title = “Select $Message File”
        $Dialog.InitialDirectory = "%UserProfile%”
		$Dialog.Filter = $Extention
        $result = $Dialog.ShowDialog()
    }

    end
    {
        If($result -eq “OK”)
        {
            $inputFile = $Dialog.FileName
            return $inputFile
        }
        else
        {
			return "Cancelled"
        }
    }
}
本体の前にXamlで、ユーザーに雪像先の情報を入力してもらいます。
$loadXaml =@'
        <Window
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Invoke AWS Teraterm Connection"
            FontFamily="consolas"
            Height="400" Width="400" Margin="5"
        >
            <StackPanel>
                <Label
                    Name="labeltera"
                    Content="TeraTerm execution file"
                    Height="30" Margin="2"
                    HorizontalAlignment="Center"
                />
                <Button
                    Name="bOpenFileDialogTera"
                    Content="Open tterapro.exe"
                    Height="30" Margin="5"
                    HorizontalAlignment="Left" VerticalAlignment="Top"
                />
                <TextBox
                    Name="textboxTera"
                    Text="C:\Program Files (x86)\teraterm\ttermpro.exe"
                    Background="#00AA88"
                    Height="25" Margin="5"
                />
                <Label
                    Name="labelkeyFile"
                    Content="Pem Key :"
                    Height="30" Margin="2"
                    HorizontalAlignment="Center"
                />
                <Button
                    Name="bOpenFileDialogkeyFile"
                    Content="Open Pem File"
                    Height="30" Margin="5"
                    HorizontalAlignment="Left" VerticalAlignment="Top"
                />
                <TextBox
                    Name="textboxkeyFile"
                    Text="C:\Program Files (x86)\teraterm\RSA\rsa.pem"
                    Background="#00AA88"
                    Height="25" Margin="5"
                />
                <Label
                    Name="labelip"
                    Content="Input AWS Server IP or Host Name"
                    Height="30" Margin="2"
                    HorizontalAlignment="Center"
                />
                <TextBox
                    Name="textboxIP"
                    Text=""
                    Background="#FFFFFF"
                    Height="25" Margin="10"
                />
                <Button
                    Name="buttonOK"
                    Content="OK"
                    FontSize="14"
                    Foreground="#FFFFFF"
                    Background="#505050"
                    Height="40"
                    Margin="5"
                />
            </StackPanel>
        </Window>
'@
で、なんちゃってコードびはいxxx
function Show-XAMLSystemTime{


    [CmdletBinding(
        SupportsShouldProcess   = $false,
        ConfirmImpact       = "none",
        DefaultParameterSetName = ""
    )]


    param
    (
        [Parameter(
        HelpMessage = "Input path of ....",
        Position = 0,
        Mandatory = $false,
        ValueFromPipeline = $true,
        ValueFromPipelineByPropertyName = $true
        )]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({Test-Path $_.FullName})]
        [IO.FileInfo[]]
        $path,


        [Parameter(
        HelpMessage = "Enter tbind xaml @`...`@ to load.",
        Position = 0,
        Mandatory = $true,
        ValueFromPipeline = $true,
        ValueFromPipelineByPropertyName = $true
        )]
        [ValidateNotNullOrEmpty()]
        [string]
        $loadXaml,


        [Alias("PassThru")]
        [switch]
        $PassThrough
    )


    begin
    {
        try
        {
            # Add-Typeでアセンブリをロードする
            Add-Type -AssemblyName presentationframework
        }
        catch
        {
            #Alread Type added.
        }


        try
        {
            [xml]$xaml = $loadXaml
        }
        catch
        {
        }
    }


    process
    {
        $reader=(New-Object System.Xml.XmlNodeReader $xaml)
        $window=[Windows.Markup.XamlReader]::Load( $reader )

        $bOpenFileDialogTera = $window.FindName("bOpenFileDialogTera")
        $textboxTera = $window.FindName("textboxTera")
        $bOpenFileDialogkeyFile = $window.FindName("bOpenFileDialogkeyFile")
        $textboxkeyFile = $window.FindName("textboxkeyFile")
        $textboxIP = $window.FindName("textboxIP")
        $buttonOK = $window.FindName("buttonOK")

        $jsonFile = "Connection.json"


        #Check json file exist or not
        if(Test-Path .\$jsonFile)
        {
            $jsonRead = Get-Content $jsonFile | ConvertFrom-Json
            $textboxTera.Text = $jsonRead.tera
            $textboxkeyFile.Text = $jsonRead.keyFile
            $textboxIP.Text = $jsonRead.ip
            $textboxIP.Text = $jsonRead.ip
        }


        #bOpenFileDialogTera
        $buttonTera_clicked = $bOpenFileDialogTera.add_Click
        $buttonTera_clicked.Invoke({
		$teraResult = Get-File -Message "tterapro.exe" -Extention “exe files (*.exe)|*.exe”
		if ($teraResult -ne "Cancelled")
		{
		 	$textboxTera.Text = $TeraResult
		}
		})


		#bOpenFileDialogkeyFile
        $buttonkeyFile_clicked = $bOpenFileDialogkeyFile.add_Click
        $buttonkeyFile_clicked.Invoke({
		$keyFileResult = Get-File -Message ".pem" -Extention “Pem files (*.pem)|*.pem”
		if ($keyFileResult -ne "Cancelled")
		{
		 	$textboxkeyFile.Text = $keyFileResult
		}
		})


        #buttonOK event to close window
        $buttonOK_clicked = $buttonOK.add_Click
        $buttonOK_clicked.Invoke({
        $Window.close()})

        #buttonOK event to close window
        $buttonOK_clicked = $buttonOK.add_Click
        $buttonOK_clicked.Invoke({
        $Window.close()})


        # region / TODO: Keydown Eventの検知
        <#
        #textboxip Keydown Event
        $textboxIP_keydown = $textboxIP.KeyDown
        if($textboxIP_keydown.Key -eq [System.Windows.Forms.Keys]::Enter)
        {
            $textboxIP_keydown.Invoke({$textboxkeyFile.Text = 123})
        }
        #>


    }


    end
    {
        $window.ShowDialog() > $null


        #return to Powershell
        $result = [PSCustomObject]@{
            tera=$textboxTera.Text
            keyFile=$textboxkeyFile.Text
            ip=$textboxIP.Text.Trim()
        }


        $result | ConvertTo-Json -Compress | Out-File .\connection.json
        return $result
    }
}
teratermに接続するためのfunction作成します。
function Enter-Teraterm{
パラメータは同様に。
    [CmdletBinding(
        SupportsShouldProcess = $false,
        ConfirmImpact = "none"
    )]

    param
    (
    [Parameter(
    HelpMessage = "Input path of Terterm Pro execution file 'ttermpro.exe' exists",
    Position = 0
    )]
    [ValidateScript({Test-Path $_})]
    [ValidateNotNullOrEmpty()]
    [string]
    $teraterm="C:\Program Files (x86)\teraterm\ttermpro.exe",


    [Parameter(
    HelpMessage = "Input Connecting Hot IP/NetBIOS to connect",
    Position = 1
    )]
    [ValidateNotNullOrEmpty()]
    [string]
    $ip,


    [Parameter(
    HelpMessage = "Input Port number to connect",
    Position = 2
    )]
    [ValidateNotNullOrEmpty()]
    [int]
    $port="22",


	[Parameter(
    HelpMessage = "Input SSH type : default value = /ssh2",
    Position = 3
    )]
    [ValidateSet("/ssh1","/ssh2")]
    [ValidateNotNullOrEmpty()]
    [string]
    $ssh="/ssh2",


    [Parameter(
    HelpMessage = "Input Authentication type : default value = publickey",
    Position = 4
    )]
    [ValidateSet("password","publickey","challenge","pageant")]
    [ValidateNotNullOrEmpty()]
    [string]
    $auth="publickey",


    [Parameter(
    HelpMessage = "Input username to login : default value = ec2-user",
    Position = 5
    )]
    [ValidateNotNullOrEmpty()]
    [string]
    $user="ec2-user",


    [Parameter(
    HelpMessage = "Input rsa key path : default value = C:\Program Files (x86)\teraterm\RSA\purplehosts.pem",
    Position = 6
    )]
    [ValidateScript({Test-Path $_})]
    [ValidateNotNullOrEmpty()]
    [string]
    $keyFile="C:\Program Files (x86)\teraterm\RSA\purplehosts.pem"

    )
プロセスと引数を触るため、.NETを呼び出します。
    begin
    {
		try
		{
			$process = New-Object System.Diagnostics.Process
		}
		catch
		{
		}


		try
		{
			$process.StartInfo = New-Object System.Diagnostics.ProcessStartInfo @($teraterm)
		}
		catch
		{
		}
    }
接続先のIPとportをstringがっちゃんこします。
    process
    {
		try
		{
			[string]$connection = $ip + ":" + $port
		}
		catch
		{
		}
実行ディレクトリを指示して…
$process.StartInfo.WorkingDirectory = (Get-Location).Path
引数を指定し
$process.StartInfo.Arguments = "$connection $ssh /auth=$auth /user=$user /keyfile=$keyFile"
tterapro.exeを起動します。
$process.Start() > $null
最後にfunctionを閉じます。
}
後は実行しましょう。 まずはXaml画面を表示して、ユーザー操作の値を受け取ります。
# Open XAML View and get paramters
$WPFresult = Show-XAMLSystemTime -loadXaml $loadXaml
次に、Xaml結果をコマンドレットに渡して実行します。
# Connection (Keyfile not allowed contain space)
Enter-Teraterm -teraterm $WPFresult.tera -ip $WPFresult.IP -keyFile $WPFresult.keyFile
ぜひ、機会がある人はどうぞ! 眠いのでスクリーンショットは許してくださいー コード全文です。(18/Apr/2013)
function Get-File{


    [CmdletBinding(
        SupportsShouldProcess = $false,
        ConfirmImpact = "none"
    )]

    param
    (
    [Parameter(
    Position = 0
    )]
    [ValidateNotNullOrEmpty()]
    [string]
    $Message,


	[Parameter(
    Position = 1
    )]
    [ValidateNotNullOrEmpty()]
    [string]
    $Extention


	)


    begin
    {
		[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") > $null
        $Dialog = New-Object System.Windows.Forms.OpenFileDialog
    }


    process
    {
        $Dialog.Title = “Select $Message File”
        $Dialog.InitialDirectory = "%UserProfile%”
		$Dialog.Filter = $Extention
        $result = $Dialog.ShowDialog()
    }


    end
    {
        If($result -eq “OK”)
        {
            $inputFile = $Dialog.FileName
            return $inputFile
        }
        else
        {
			return "Cancelled"
        }
    }
}


function Show-XAMLSystemTime{


    [CmdletBinding(
        SupportsShouldProcess   = $false,
        ConfirmImpact       = "none",
        DefaultParameterSetName = ""
    )]


    param
    (
        [Parameter(
        HelpMessage = "Input path of ....",
        Position = 0,
        Mandatory = $false,
        ValueFromPipeline = $true,
        ValueFromPipelineByPropertyName = $true
        )]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({Test-Path $_.FullName})]
        [IO.FileInfo[]]
        $path,


        [Parameter(
        HelpMessage = "Enter tbind xaml @`...`@ to load.",
        Position = 0,
        Mandatory = $true,
        ValueFromPipeline = $true,
        ValueFromPipelineByPropertyName = $true
        )]
        [ValidateNotNullOrEmpty()]
        [string]
        $loadXaml,


        [Alias("PassThru")]
        [switch]
        $PassThrough
    )


    begin
    {
        try
        {
            # Add-Typeでアセンブリをロードする
            Add-Type -AssemblyName presentationframework
        }
        catch
        {
            #Alread Type added.
        }


        try
        {
            [xml]$xaml = $loadXaml
        }
        catch
        {
        }
    }


    process
    {
        $reader=(New-Object System.Xml.XmlNodeReader $xaml)
        $window=[Windows.Markup.XamlReader]::Load( $reader )

        $bOpenFileDialogTera = $window.FindName("bOpenFileDialogTera")
        $textboxTera = $window.FindName("textboxTera")
        $bOpenFileDialogkeyFile = $window.FindName("bOpenFileDialogkeyFile")
        $textboxkeyFile = $window.FindName("textboxkeyFile")
        $textboxIP = $window.FindName("textboxIP")
        $buttonOK = $window.FindName("buttonOK")

        $jsonFile = "Connection.json"


        #Check json file exist or not
        if(Test-Path .\$jsonFile)
        {
            $jsonRead = Get-Content $jsonFile | ConvertFrom-Json
            $textboxTera.Text = $jsonRead.tera
            $textboxkeyFile.Text = $jsonRead.keyFile
            $textboxIP.Text = $jsonRead.ip
            $textboxIP.Text = $jsonRead.ip
        }


        #bOpenFileDialogTera
        $buttonTera_clicked = $bOpenFileDialogTera.add_Click
        $buttonTera_clicked.Invoke({
		$teraResult = Get-File -Message "tterapro.exe" -Extention “exe files (*.exe)|*.exe”
		if ($teraResult -ne "Cancelled")
		{
		 	$textboxTera.Text = $TeraResult
		}
		})


		#bOpenFileDialogkeyFile
        $buttonkeyFile_clicked = $bOpenFileDialogkeyFile.add_Click
        $buttonkeyFile_clicked.Invoke({
		$keyFileResult = Get-File -Message ".pem" -Extention “Pem files (*.pem)|*.pem”
		if ($keyFileResult -ne "Cancelled")
		{
		 	$textboxkeyFile.Text = $keyFileResult
		}
		})


        #buttonOK event to close window
        $buttonOK_clicked = $buttonOK.add_Click
        $buttonOK_clicked.Invoke({
        $Window.close()})

        #buttonOK event to close window
        $buttonOK_clicked = $buttonOK.add_Click
        $buttonOK_clicked.Invoke({
        $Window.close()})


        # region / TODO: Keydown Eventの検知
        <#
        #textboxip Keydown Event
        $textboxIP_keydown = $textboxIP.KeyDown
        if($textboxIP_keydown.Key -eq [System.Windows.Forms.Keys]::Enter)
        {
            $textboxIP_keydown.Invoke({$textboxkeyFile.Text = 123})
        }
        #>


    }


    end
    {
        $window.ShowDialog() > $null


        #return to Powershell
        $result = [PSCustomObject]@{
            tera=$textboxTera.Text
			keyFile=$textboxkeyFile.Text
            ip=$textboxIP.Text.Trim()
        }


        $result | ConvertTo-Json -Compress | Out-File .\connection.json
        return $result
    }
}




$loadXaml =@'
        <Window
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Invoke AWS Teraterm Connection"
            FontFamily="consolas"
            Height="400" Width="400" Margin="5"
        >
            <StackPanel>
                <Label
                    Name="labeltera"
                    Content="TeraTerm execution file"
                    Height="30" Margin="2"
					HorizontalAlignment="Center"
                />
                <Button
                    Name="bOpenFileDialogTera"
                    Content="Open tterapro.exe"
                    Height="30" Margin="5"
					HorizontalAlignment="Left" VerticalAlignment="Top"
                />
                <TextBox
                    Name="textboxTera"
                    Text="C:\Program Files (x86)\teraterm\ttermpro.exe"
                    Background="#00AA88"
                    Height="25" Margin="5"
                />
                <Label
                    Name="labelkeyFile"
                    Content="Pem Key :"
                    Height="30" Margin="2"
					HorizontalAlignment="Center"
                />
                <Button
                    Name="bOpenFileDialogkeyFile"
                    Content="Open Pem File"
                    Height="30" Margin="5"
					HorizontalAlignment="Left" VerticalAlignment="Top"
                />
                <TextBox
                    Name="textboxkeyFile"
                    Text="C:\Program Files (x86)\teraterm\RSA\rsa.pem"
                    Background="#00AA88"
                    Height="25" Margin="5"
                />
                <Label
                    Name="labelip"
                    Content="Input AWS Server IP or Host Name"
                    Height="30" Margin="2"
					HorizontalAlignment="Center"
                />
                <TextBox
                    Name="textboxIP"
                    Text=""
                    Background="#FFFFFF"
                    Height="25" Margin="10"
                />
                <Button
                    Name="buttonOK"
                    Content="OK"
                    FontSize="14"
                    Foreground="#FFFFFF"
                    Background="#505050"
                    Height="40"
                    Margin="5"
                />
            </StackPanel>
        </Window>
'@




function Enter-Teraterm{

    [CmdletBinding(
        SupportsShouldProcess = $false,
        ConfirmImpact = "none"
    )]

    param
    (
    [Parameter(
    HelpMessage = "Input path of Terterm Pro execution file 'ttermpro.exe' exists",
    Position = 0
    )]
    [ValidateScript({Test-Path $_})]
    [ValidateNotNullOrEmpty()]
    [string]
    $teraterm="C:\Program Files (x86)\teraterm\ttermpro.exe",


    [Parameter(
    HelpMessage = "Input Connecting Hot IP/NetBIOS to connect",
    Position = 1
    )]
    [ValidateNotNullOrEmpty()]
    [string]
    $ip,


    [Parameter(
    HelpMessage = "Input Port number to connect",
    Position = 2
    )]
    [ValidateNotNullOrEmpty()]
    [int]
    $port="22",


	[Parameter(
    HelpMessage = "Input SSH type : default value = /ssh2",
    Position = 3
    )]
    [ValidateSet("/ssh1","/ssh2")]
    [ValidateNotNullOrEmpty()]
    [string]
    $ssh="/ssh2",


    [Parameter(
    HelpMessage = "Input Authentication type : default value = publickey",
    Position = 4
    )]
    [ValidateSet("password","publickey","challenge","pageant")]
    [ValidateNotNullOrEmpty()]
    [string]
    $auth="publickey",


    [Parameter(
    HelpMessage = "Input username to login : default value = ec2-user",
    Position = 5
    )]
    [ValidateNotNullOrEmpty()]
    [string]
    $user="ec2-user",


    [Parameter(
    HelpMessage = "Input rsa key path : default value = C:\Program Files (x86)\teraterm\RSA\rsa.pem",
    Position = 6
    )]
    [ValidateScript({Test-Path $_})]
    [ValidateNotNullOrEmpty()]
    [string]
    $keyFile="C:\Program Files (x86)\teraterm\RSA\rsa.pem"

    )


    begin
    {
		try
		{
			$process = New-Object System.Diagnostics.Process
		}
		catch
		{
		}

		try
		{
			$process.StartInfo = New-Object System.Diagnostics.ProcessStartInfo @($teraterm)
		}
		catch
		{
		}
    }


    process
    {
		try
		{
			[string]$connection = $ip + ":" + $port
		}
		catch
		{
		}

		$process.StartInfo.WorkingDirectory = (Get-Location).Path


		#"C:\Program Files (x86)\teraterm\ttermpro.exe" 192.168.0.100:22 /ssh2 /auth=publickey /user=user /keyfile=D:\key.rsa
		$process.StartInfo.Arguments = "$connection $ssh /auth=$auth /user=$user `"/keyfile=$keyFile`""
		$process.Start() > $null
    }

}


# Open XAML View and get paramters
$WPFresult = Show-XAMLSystemTime -loadXaml $loadXaml


# Connection (Keyfile not allowed contain space)
Enter-Teraterm -teraterm $WPFresult.tera -ip $WPFresult.IP -keyFile $WPFresult.keyFile