脳筋なんでもSSOを作成する【Windows】【Excel】【PowerShell】

### 作成の経緯
PowerShellでキーボード操作ができるので、Excelファイルのパスワード保護と組み合わせて、シングルサインオンみたいな感じにしようと思い作成しました。
パスワードをスクリプト内に組み込むよりかはセキュアですが、その他のログイン方法より非セキュアだと思うので、オープン環境での利用は自己責任でお願いします。
構築時等のクローズ環境等なら便利かもしれません。

## Excelの準備
以下のような形式でエクセルファイルを作成してマクロ有効ブックの拡張子(`.xlsm`)で保存してください。今回は`CSVmacro.xlsm`という名前で保存します。今回はWEBブラウザ(chrome)からログインする形にするので、ウェブクライアントのIPアドレス、ユーザー名、パスワードを記載してください。ハッシュ部分のキーに関してはハッシュ値ではなく、ロケーション、アプライアンス、何号機かのイニシャルをまとめた形で作成します。

例)東京サーバー、vCenter、1号機　> tv1

|HASH|IP|USER|PASSWORD|
|:--:|:--:|:--:|:--:|
|tv1|192.168.XXX.XXX|admin1|password1|
|te1|192.168.XXX.XXX|root1|password2|
|te2|192.168.XXX.XXX|root2|password3|

作成したら、「ファイル」>「情報」>「ブックの保護」から「パスワードを使用して暗号化」を選択し、任意のパスワードを入力します。

### マクロの登録
現在のブックでcreateCSVという名前でcsvを出力するマクロを作成します。

:::note info
#### マクロを初めて利用する場合
「ファイル」>「オプション」>「リボンのユーザー設定」から、右のメインタブにある「開発」にチェックをしておきましょう。
:::

「開発」タブの「マクロ」を押下し、マクロ名に「createCSV」と入力し、「作成」を押下します。

エディタ内に以下を貼り付けます。SubとEndはすでにあると思うので不要です。

~~~
Sub createCSV()

 Dim wkbk As Workbook
 Dim wkst As Worksheet
 Dim i As Long
 Dim filename As String

 Set wkbk = ActiveWorkbook
 Set wkst = wkbk.ActiveSheet

 filename = wkst.Name & ".csv"
 fullpath = ThisWorkbook.Path & "¥" & filename
 
 Open fullpath for Output As #1
  With ActiveSheet
   For i = 1 To .Cells(Rows.Count, 1).End(xlUp).Row
    Print #1, .Cells(i, "A") & "," & .Cells(i, "B") _
    & "," & .Cells(i, "C") & "," & .Cells(i, "D")
   Next i
  End With
 Close #1

End Sub
~~~
A1から最終行までのA~D列を読み込んで、<シート名>.csv形式で出力するものです。シート名は今回はデフォルトのSheet1.csvの形で後ろのスクリプトも作成していきます。

## PowerShellスクリプトの作成
今回のスクリプトは大きく分けて三段階構成です。

+ エクセルを開いてマクロを実行する
+ スクリプトで生成されたcsvファイルを読み込む
+ 読み込んだ情報からWEBブラウザでログインする

序盤はIT感がありますが、最後がゴリゴリの脳筋ログインなのでお気をつけください。ただ見た目的には脳筋なのにすごくITしてる雰囲気が味わえます。

### エクセルを開いてマクロを実行する
↓こちらの方のを参考にして作成しました。

https://qiita.com/Mount/items/b2ea4d4a4fe78cb8bbb2

~~~
#エクセルのパスワードを対話式で入力
$ExPass = Read-Host "パスワードを入力"

#エクセルファイルを指定して起動
$xlApp = New-Object -ComObject Excel.Application
$macroEx = Get-ChildItem -Path ${HOME} -Filter "*CSVmacro*" -Recurse 2>$null |Convert-Path
$xlBook = $xlApp.Workbooks.Open($macroEx,[Type]::Missing, [Type]::Missing, [Type]::Missing, $ExPass)
$xlApp.Run("createCSV")

#完了したので停止
$xlBook.Close()
[System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($xlApp)|Out-null
Stop-Process -Name EXCEL

~~~
ここでパスワードで保護したことで1ミリくらいセキュアになります。

### スクリプトで生成されたcsvファイルを読み込む

さて、csvが作成できたので、次はそれを読み込み変数に格納していきます。

~~~
#csvデータのフルパスを取得
$CSVPath = Get-ChildItem -Path ${HOME} -Filter "Sheet1.csv" -Recurse 2>$null |Convert-Path

#csvデータを変数に格納
$CSVData = Import-CSV $CSVPath

~~~
これでcsvデータを取り込めました。ブックをCドライブ直下等に保存せずにホームディレクトリ配下のどこか(デスクトップやドキュメント等)に入れている前提でパスは作成しています。

### 読み込んだ情報からWEBブラウザでログインする

まずはじめに、対話式でどれに入りたいかを指定していきます。IP、ユーザー名、アドレスが完全な状態で同じファイルに入っているのはパスワードを付けているといえど、やはり危ない気もするので、マスクしてあるIPを置換する形で作成してみようと思います。

~~~

#ハッシュ部分の情報入力
$Loc = Read-Host "サーバーの場所のイニシャルを入力"
$Pat = Read-Host "入りたいサイトやアプライアンス等のイニシャルを入力"
$Num = Read-Host "何号機か入力"
$Uni = "${Loc}${Pat}${Num}"
$IPTail = Read-Host "IPアドレスの第3、4オクテットを入力"
~~~

これで、スクリプト実行時の入力項目の作成は完了しました。
ここからは、入力項目とデータを照合して対象を一意に絞っていきます。

~~~
#それぞれの行に対して入力項目と合致した場合にデータを変数に格納する
Foreach($row in $CSVData){
 if($row.HASH -eq $Uni){
  $UniIP = $row.IP
  $UniUSER = $row.USER
  $UniPASS = $row.PASSWORD
 }
}
$UniIP = $UniIP -replace "*XXX.XXX","${IPTail}"

#Chromeで対象のIPにhttps接続する
$Chropath = Get-ChildItem -Path c:/ -Filter "*chrome.exe*" -Recurse 2>$null |Convert-Path
Start-Process -FilePath $ChroPath -ArgumentList "https://${UniIP}"
~~~
:::note warn
#### パスワードに特殊文字を使うセキュアな方の場合
まさかこの記事を見てこんなセキュアなパスワードを設定していることはないかと思いますが、もし特殊文字を含めている場合は、パスワードの一部を置換する必要がでてきます。IPアドレスを置換する部分で一部特殊文字を以下の形に変更してください。

~~~
$UniPASS = $UniPASS -replace '%','{%}'
$UniPASS = $UniPASS -replace '$','{$}'
$UniPASS = $UniPASS -replace '+','{+}'
~~~
:::

分かる場合はChromeのパス等は検索せずに指定することで軽く素早くなります。
これで対象の情報を取り出すことができました。
ここからお楽しみの脳筋コマンドの始まりです。

~~~
#キーボード入力準備
Add-Type -AssemblyName System.Windows.Forms

#Chromeが立ち上がるのを待ちます。待ち時間がは経験による目分です（脳筋ポイント）
Start-Sleep 4

#サイトの構造によってTABの回数が異なります。また入力漏れ等が発生することもあるのでTABを打ったら程よくスリープするようにfunction化しておきましょう。
function TABSleep{
[System.Windows.Forms.SendKeys]::SendWait("{TAB}")
Start-Sleep -m 200
}

#サイトごとにタブを打つ回数等を修正しましょう。（脳筋ポイント）今回はログイン画面で一度タブを打つとユーザー部分が入力できる場合で作成しています。
switch($Pat){
 v {
  TABSleep
  System.Windows.Forms.SendKeys]::SendWait("${UniUSER}")
  TABSleep
  [System.Windows.Forms.SendKeys]::SendWait("${UniPASS}")
  TABSleep
  [System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
 }
}

#CSVの削除
Remove-Item -Path $CSVPath
~~~
switch部分のコマンドは環境やサイトによってかなり異なるので、参考程度に見ながら、スリープ時間やタブの回数等を調整してみてください。HASH部分を伸ばすことで、Teraterm用、WEBクライアント用、RDP用等色々なパターンでのログインができるようになります。