【TeraTerm】Teratermマクロ備忘録

# はじめに
TeraTermはいまだに現場での利用率が高いなと思います。
個人的にTeratermマクロは書き方が特徴的で少し苦手なのですが使えるに越したことはないのでちょっと書くようになりました。

ただどうせすぐ忘れてしまうので、備忘がてら残しておこうと思います。

# パスワードログインマクロ

```text
;=====================================
;接続情報
hostName = "<IPアドレス>"
userName = "<ユーザ名>"
passWord = "<パスワード>"
;======================================

;======================================
;ログ設定
getdir dir
setdir dir
getdate logFileName '%Y%m%d_%H%M%S.log'
path = dir
strconcat path "\log\"
foldersearch path
if result = 0 then
    foldercreate path
endif
strconcat path logFileName
;======================================

getConnection = hostName
strconcat getConnection ':22/ssh2 /auth=password /user='
strconcat getConnection userName
strconcat getConnection ' /passwd='
strconcat getConnection passWord

;messagebox getConnection "確認"

;接続
connect getConnection

;ログ記録
logopen path 0 1 0 1

```

## パスワードログインマクロ制作メモ

### string(文字列)をconcatenate(結合)の巻
TeraTermマクロはstrconcatで文字列を結合していくのが特徴的
恐らくクォーテーションで囲まれた文字列の中で変数を展開することができないかもしくは難しいためにこういう書き方をすると思われる。

### TeraTerm「最初にconnect書かないと君の話は聞かないよ」の巻
最初logopenを「ログ設定」のブロックに書いていたけれども、``Link macro first Use 'connect' macro.``なるエラーが発生。
文字通り、始めにconnectをしないとだめらしい。
マクロとTeraterm間のリンクが確立してないとダメだとかなんとか...(よくわからん)

### ログ記録して不正防止の巻
ログインマクロでログインする際は自動でログ記録もしたかったのでこれも設定。
``foldersearch``はパラメータとして選択したパスのフォルダがない場合0をリターンする。
なのでif文を組み合わせることで、フォルダが無い場合に作成するといったような動きを作ることも可能
(個人的にサーチしてない場合0より-1っぽい印象がある...)

logopenコマンドはファイルパスの後ろに謎の数字が羅列されている。
これは特定の機能のオンオフを制御するフラグである。
- 先頭の0はテキストモードで記録する意味する。
- 2つ目の1はファイルが存在する場合追記することを意味する。
- 3つ目の0はASCII制御文字を記録する
- 4つ目の1はタイムスタンプを記録する

反対の値はだいたいその逆の効果になる。

特に先頭の0は個人的に必須。
バイナリモードだとANSIエスケープシーケンスも記録されるのでscriptコマンドの悲劇が:scream:

messageboxはデバッグ用として役立つ。

# コマンド実行マクロ

```text
wait userName

sendln "date"
wait userName
sendln "whoami"
wait userName
sendln "hostname"
wait userName

sendln "echo $?"
wait userName
for i 1 6
    recvln
next

messagebox inputstr "recvlnの取得内容確認"
strcompare inputstr '0'
messagebox result "結果"
if result=0 then
    messagebox "success" "通知"
else
    messagebox "failure" "通知"
endif

```

## コマンド実行マクロ制作メモ

### マクロ君「俺のスピードについてこれるかい？」の巻
``wait``コマンドを使って特定の文字が出現するまで後続のコマンドの実行を待っている。
これが地味に重要で、入れないとコマンドの実行結果を待たずしてどんどんマクロの処理が進んでしまい意図しない挙動となる。
プロンプトに含まれる文字を条件にすると良いと思われる。

### シェル上でのコマンド実行は``sendln``
コマンドは``sendln``にシェルコマンドを渡すことでコマンドを実行できる。
lnの無い``send``もあるらしいけど恐らく改行の有無でしょう。
(Javaのprintとprinlnのような関係みたいな)

### recvlnの闇
コマンドの実行結果を基に分岐できたらいいなと思い、
``echo $?``でコマンドの実行結果を確認している。
この値を取得してif文でうまいこと条件判定できたらいいのだけれどここは一筋縄ではいかなかった。
コンソール上の値を取得するには``recvln``なるコマンドを使うのだけれども、これは「1行分の文字を受信します」とのこと。
どの時点の1行分の文字だよ:rolling_eyes:
と思いながらmessageboxで確認していく。
6回目のrecvlnで0が取得できた...がコンソールに見ている行数と絶妙に一致していない。
これは謎のコマンドですね:droplet:

とりあえず今回のケースでは6回目で取得できたということで、recvlnを6回打つ必要があるのだが、そのまま打つとあまりにみっともないのでfor文で記述。
このfor文は``for　変数 始値　終値 ~ next``のBasicライクな記述ですね。

ifといいforといいここら辺の制御構造がちゃんとある感じから一端のプログラミング言語ですね。

### コマンド実行結果を判定分岐の巻
recvlnで取得した値はシステム変数``inputstr``に格納される。
``strcompare``という文字列を比較するコマンドで、``inputstr``と"0"を比較する。
判定の結果はシステム変数``result``に格納される。
あとはif文で``result``と数値の0を比較することで、一つ前のコマンド実行結果をもとに分岐できる。
最初if文に``inputstr``を直接判定式の中に使ったがこれはうまくいかなかった。
エラー内容は``Type mismatch.``で型の問題であることが伺える。
``inputstr``というサフィックスからも文字列型であると思われ、数値の0と比較しているのでこれが先のエラーを引き起こすのだろう。
なので、strcompareの結果(result)を判定式に使うことにした。

ちなみに、`if inputstr="0" then`のような書き方をしても同様に"Type mismatch."が発生した。
もしかしたら、if文の条件式は文字列比較はできないのかもしれない。


## コマンドラインからTeraTermマクロを実行(PowerShell)

```Powershell:ttl実行
$ttl = "C:\Users\Username\Documents\TeraTerm\login.ttl"
$param2 = "echo"
$param3 = "test"
Start-Process "C:\Program Files (x86)\teraterm\ttpmacro.exe" -Wait -ArgumentList $ttl, $param2,$param3
```

```text:ttlの中身
~ログイン処理省略

;コマンドラインから渡された値を整形してコマンドを実行
cmd = param2
strconcat cmd " "
strconcat cmd param3
;messagebox cmd "確認"
sendln cmd
```

### PowerShellからTeraTermマクロを実行するには一筋縄ではいかないぜの巻
ttlはコマンドラインから実行することができる。
batで実行する場合は``ttpmacro.exe [オプション] <ttl> [arg]``みたいな形式で実行できるみたいだけどPowershellからだとうまくいかなかった。
Powershellで実行する場合は、``Start-Process``コマンドレットを使用して、ttpmacro.exeを起動させる。
``-ArgumentList``で引数を渡していくといった流れになる。
第一引数はttlそれ以降はマクロ上で使うための値を受け渡すことができる。

### TeraTermマクロでコマンドライン引数の値を使用するの巻
引数として渡した値をマクロ上で使用するにはシステム変数``param``を使う。
~~paramはparam[0]~param[9]まで連番が振られているらしい。~~
- ~~0番目はコマンドラインの文字列全体が格納~~
- 1番目はマクロファイル名が格納(パス情報は含まずファイル名だけ)
とのことなので、実際にユーザが任意で使えるのは2~9の間ということになる。
::: note warn
param0を参照すると``variable not initialized``が表示されたためそもそもparam1スタートかもしれません。
:::

### TeraTerm「俺の中ではスペースが引数の区切り文字だから」の巻
マクロファイル側ではこれをシェル上で使えるコマンドラインとして成型する。
簡潔に言えばstrconcatで``param2 + スペース + param3``の形で連結する。
そして連結した文字列を``sendln``で実行する。

この結合が面倒だな~と思ってpowershell上でコマンドラインを成型した状態で引数として渡しても失敗した。
例えば以下のような感じ
```powershell
$ttl = "C:\Users\Username\Documents\TeraTerm\login.ttl"
$param2 = "echo test"
Start-Process "C:\Program Files (x86)\teraterm\ttpmacro.exe" -Wait -ArgumentList $ttl, $param2
```

この場合"echo"までしかparam2に格納されていなかった。
testをクォーテーションで囲ってみたりしたけど変わらず...
Teraterm側が空白を区切り文字として認識しているようで、
testはparam3に格納されていたよ。
なのでおとなしくマクロ上で成型してあげるのが良さそう。

# 余談
コマンドのリターンを変数に格納するといった一般的な仕組みではなく、
システム変数に自動格納される点が特徴的だなと思いました。

多分続く...

# 参考
http://ttm.jimba.ddo.jp/adiary.cgi/teraterm/

http://teraterm.feasible-lab.com/