備考欄に感想を書くタイプのエンジニア

それで出世が遅れ(ry

AsSecureStringの値はパスワード欄にそのまま入れると死ぬ

PowerShell 内でパスワードの情報を扱う際に -AsSecureString というパラメーターを使ったり ConvertTo-SecureString コマンドを使ったりするシーンがあるかと思います。SecureString にしない場合はこう。

PS > $Password = Read-Host -Prompt "Enter your Password..."
Enter your Password...: Password

PS > $password
Password

-AsSecureString パラメーターを付けた場合はこう。

PS > $Password = Read-Host -AsSecureString -Prompt "Enter your Password..."
#パスワード入力のためのポップアップは表示されるが、入力した内容は伏字になる
PS > $Password
System.Security.SecureString

ということで、そのままだとパスワードの値そのものは利用できないという認識だったのですが、 Windows PowerShell 4.0 for .NET Developers を見てると次のような形で Outlook.com に接続してサインインまでしてしまおうとしていて「?」となったわけです。

$EmailAddress = Read-Host -Prompt "Enter your Microsoft Account.."
$Password = Read-Host -AsSecureString -Prompt "Enter your Password..."
$ie = New-Object -ComObject InternetExplorer.Application
$ie.visible = $true
$ie.navigate("https://outlook.com")
while ($ie.Busy){Start-Sleep -Milliseconds 500}
$doc = $ie.document
$tbUsername = $doc.getElementByID("i0116")
$tbUsername.value = $EmailAddress
$tbPassword = $doc.getElementByID("i0118")
$tbPassword.value = $Password
$tbnSubmit = $doc.getElementByID("idSIButton9")
$tbnSubmit.Click()

結構回りくどい感じですが、それよりも $Password で SecureString になっているパスワードをそのまま突っ込んでいますし、実際にこのコードを実行するとサインインに失敗します。ではどうするか。1つは SecureString を平文に戻す方法です。

$EmailAddress = Read-Host -Prompt "Enter your Microsoft Account.."
$Password = Read-Host -AsSecureString -Prompt "Enter your Password..."
$ie = New-Object -ComObject InternetExplorer.Application
$ie.visible = $true
$ie.navigate("https://outlook.com")
while ($ie.Busy){Start-Sleep -Milliseconds 500}
$ie.document.getElementByID("i0116").value = $EmailAddress
$ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
$PasswordPlain = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ptr)
$ie.document.getElementByID("i0118").value = $PasswordPlain
$ie.document.getElementByID("idSIButton9").Click()

今回は COM を使って元のパスワードに戻していますが、それでもまだ面倒くさい感じがします。もう一つの方法は Get-Credential にアカウント情報を持たせてあげる形です。というより@guitarrapc_tech 氏が下のように言っていたのを見て、そう言えば書籍に書いてあることが間違えているのに気づいたことを思い出して書いているだけです()

$cred = Get-Credential -Message "Input username for login"
$ie = New-Object -ComObject InternetExplorer.Application
$ie.visible = $true
$ie.navigate("https://outlook.com")
while ($ie.Busy){Start-Sleep -Milliseconds 500}
$ie.document.getElementByID("i0116").value = $cred.UserName
$ie.document.getElementByID("i0118").value = $cred.GetNetworkCredential().Password
$ie.document.getElementByID("idSIButton9").Click()

こちらのほうが比較的シンプルな感じでしょうか。。。他にいい方法があれば教えてくだしあ。 ※それでもやはりパスワードの情報を利用する際には GetNetworkCredential メソッドを使わないと正しくパスワード情報を得られなくて死にます。