[07] PowerShell実践例 ... GUIアプリの消極的自動操作



|本シリーズのトップページ|
|:--|
|https://qiita.com/robozushi10/items/0b0605257ad39bc22895|


# はじめに

Windows での CI の場合、CUI がサポートされておらず、<font color="red">**強引**</font> に GUI アプリのメニュを操作せざるを得ない状況がある.

一例としては、次のような操作である
> ・「名前を付けて保存」を選択する
↓
・ファイル名を入力する
↓
・「保存」ボタンを押す


これを (繰り返しになるが <font color="red">**強引**</font>  に) 自動化したときの例を記す.

なお、この手法は バッチがマウスおよびキーボードを自動操作しているので、バッチ実行中に人がマウスやキーボードを使うと動作しなくなる.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1246056/2076a054-cd39-170b-e38c-7d62d27fdcb4.png)
※ 画像は [NEC LAVIE 様](https://faq.nec-lavie.jp/qasearch/1007/app/servlet/relatedqa?QID=014610) よりお借りした

　

# 環境

```
Windows 10 Pro
PowerShell バージョン 6系
```


# 処理概要

次の 1〜4 の処理をする

```
1. 対象の GUI アプリ「ABC」を最前面表示する
　　このとき、アプリ「ABC」は "最小表示" になっていない前提である.
　　最小表示だと厄介である...

2. ツールバーより「ファイル」→ 「名前を付けて保存する」を選択する.
　　なお、「名前を付けて保存する」メニュは、上から 4番目に存在するものとする

3. 保存先のパスを入力する
　　今回は保存先を「C:\Users\foo\Documents\サンプル.xlsx」とする.
　　なおユーザ名を「foo」としているので、適宜読み替えること.

4. 「保存」ボタンを押す

```

　

# 詳細

※下記はコードを抜粋したため、文法エラーが生じるかも知れない.

## 1. 対象の GUI アプリ「ABC」を最前面表示する

```powershell
# GUI を使うための "おまじない" (System.Windows.Formsのインポート) をする. 
add-type -AssemblyName System.Windows.Forms

# プロセス名「ABC」を最前面 (== アクティブ) にする.
add-type -AssemblyName microsoft.VisualBasic
add-type -AssemblyName System.Windows.Forms

# プロセス「ABC」のオブジェクト $P を得る
$P = Get-Process | Where-Object { $_.Name -eq "ABC"}
if( $P -eq $null )
{
  # 「ABC」などというプロセス名が見つからなかったので終了する
  return $False
}
else
{
  # プロセスID を指定して最前面にする. 
  # このとき、アプリ「ABC」は "最小表示" になっていない前提である.
  [Microsoft.VisualBasic.Interaction]::AppActivate($P.ID);
  # 画面が最前面に変わるまでの猶予時間として 1秒待つ
  Start-Sleep 1
}
```

## 2. ツールバーより「ファイル」→ 「名前を付けて保存する」を選択する.

```powershell
# 当方の CI 環境の都合で 1秒待機が必要であった.
Start-Sleep -s 1
# Altキーを押す. ツールバーの「ファイル」が選択された状態とする
[System.Windows.Forms.SendKeys]::SendWait("%")

# ツールバーの「ファイル」メニュから 1つ目を選択する
Start-Sleep -s 1
[System.Windows.Forms.SendKeys]::SendWait("{DOWN}")

# ツールバーの「ファイル」メニュから 2つ目を選択する
Start-Sleep -s 1
[System.Windows.Forms.SendKeys]::SendWait("{DOWN}")

# ツールバーの「ファイル」メニュから 3つ目を選択する
Start-Sleep -s 1
[System.Windows.Forms.SendKeys]::SendWait("{DOWN}")

# ツールバーの「ファイル」メニュから 4つ目を選択する
Start-Sleep -s 1
[System.Windows.Forms.SendKeys]::SendWait("{DOWN}")

# 「名前を付けて保存」で Enterキーを押す
Start-Sleep -s 1
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
```

## 3. 保存先のパスを入力する

```powershell
# 「ファイル名」の入力欄に対して、保存したいファイル名を絶対パスで入力する
Start-Sleep -s 1
$O = 'C:\Users\foo\Documents\サンプル.xlsx'
[System.Windows.Forms.SendKeys]::SendWait("$O")
```

## 4. 「保存」ボタンを押す

```powershell
# 「保存(S)」を押す.
Start-Sleep -s 1
[System.Windows.Forms.SendKeys]::SendWait("%s")

# 完了. 当方の CI 環境では 1秒待機が必要であった.
Start-Sleep -s 1
```

　

# コード全文

※下記はコードを抜粋したため、文法エラーが生じるかも知れない.

```powershell
# GUI を使うための "おまじない" (System.Windows.Formsのインポート) をする. 
add-type -AssemblyName System.Windows.Forms

# プロセス名「ABC」を最前面 (== アクティブ) にする.
add-type -AssemblyName microsoft.VisualBasic
add-type -AssemblyName System.Windows.Forms

# プロセス「ABC」のオブジェクト $P を得る
$P = Get-Process | Where-Object { $_.Name -eq "ABC"}
if( $P -eq $null )
{
  # 「ABC」などというプロセス名が見つからなかったので終了する
  return $False
}
else
{
  # プロセスID を指定して最前面にする. 
  # このとき、アプリ「ABC」は "最小表示" になっていない前提である.
  [Microsoft.VisualBasic.Interaction]::AppActivate($P.ID);
  # 画面が最前面に変わるまでの猶予時間として 1秒待つ
  Start-Sleep 1
}

# 当方の CI 環境の都合で 1秒待機が必要であった.
Start-Sleep -s 1
# Altキーを押す. ツールバーの「ファイル」が選択された状態とする
[System.Windows.Forms.SendKeys]::SendWait("%")

# ツールバーの「ファイル」メニュから 1つ目を選択する
Start-Sleep -s 1
[System.Windows.Forms.SendKeys]::SendWait("{DOWN}")

# ツールバーの「ファイル」メニュから 2つ目を選択する
Start-Sleep -s 1
[System.Windows.Forms.SendKeys]::SendWait("{DOWN}")

# ツールバーの「ファイル」メニュから 3つ目を選択する
Start-Sleep -s 1
[System.Windows.Forms.SendKeys]::SendWait("{DOWN}")

# ツールバーの「ファイル」メニュから 4つ目を選択する
Start-Sleep -s 1
[System.Windows.Forms.SendKeys]::SendWait("{DOWN}")

# 「名前を付けて保存」で Enterキーを押す
Start-Sleep -s 1
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")

# 「ファイル名」の入力欄に対して、保存したいファイル名を絶対パスで入力する
Start-Sleep -s 1
$O = 'C:\Users\foo\Documents\サンプル.xlsx'
[System.Windows.Forms.SendKeys]::SendWait("$O")

# 「保存(S)」を押す.
Start-Sleep -s 1
[System.Windows.Forms.SendKeys]::SendWait("%s")

# 完了. 当方の CI 環境では 1秒待機が必要であった.
Start-Sleep -s 1
```


　

# 参考にしたサイト

| URL |
|:--|
|https://onceuponatimeit.hatenablog.com/entry/2016/02/20/004837|