実行時にPowerShell変数にテキストを一時的に保存する場合、不要になったときに変数の内容をメモリから削除する最も効率的な方法は何ですか?
Clear-Item variable:
とRemove-Variable
の両方を使用しましたが、前者でメモリの内容を無効にするのに対して、後者でメモリから何かが削除されるのはどれくらいの速さですか?
編集:なぜ私が尋ねているのかをもう少し明確にすべきでした。
多数のアプリケーションVMのRDPログインを自動化しています(アプリケーションはサービスとして実行されない、外部委託された開発者、長い話)。
そのため、各VMへの起動セッションをグループ化するスクリプトを開発しています(ほぼ完成しています)。
資格情報を保存するスクリプト関数は、read-Host
を使用してホスト名の入力を求め、次にget-credentials
を使用してドメイン/ユーザー/パスワードを取得するという考え方です。
次に、256ビットキー(資格情報を保存し、グループ起動を実行するマシン/ユーザーに固有のランタイムキー)を使用して、パスがセキュア文字列から変換されます。
VMの名前、ドメイン、ユーザー、暗号化されたパスはファイルに保存されます。セッションを開始すると、詳細が読み込まれ、パスワードが復号化され、詳細がcmdkey.exe
に渡されて、そのVMの\generic:TERMSRV
資格情報が保存され、プレーンテキストのパス変数がクリアされ、そのホストに対してmstscが起動され、数秒後に削除されます。 Windows資格情報ストアからの資格情報。 (パスワードをプレーンテキスト以外のものとしてcmdkey.exeに渡した場合、RDPセッションは誤った資格情報を受け取るか、資格情報を受け取りません)。
したがって、質問です。できるだけ短時間メモリに存在するために、平文のパスワードが必要です。
セキュリティ担当者を満足させるために、スクリプト自体はaes256で暗号化され、独自のpsホストを持つc#ラッパーがスクリプトを読み取り、復号化して実行するため、これを実行するマシンにはプレーンテキストソースはありません。 (ファイル共有の暗号化されたソースなので、効果的にキルスイッチがあり、暗号化されたスクリプトを、このアプリが無効になっているというメッセージを表示する別のスクリプトに置き換えることができます)
ストップウォッチを使用して、コマンドレットの実行時間を取得できます。これら2つのコマンドレットの間に実際には時間差はないと思います。私の目には変数を完全に削除する方が良いので、私は通常「Remove-Item」を使用しています。
$a = "TestA"
$b = "TestB"
$c = "TestC"
$d = "TestD"
$time = New-Object system.Diagnostics.Stopwatch
Start-Sleep 1
$time.Start()
$time.Stop()
$system = $time.Elapsed.TotalMilliseconds
Write-Host "Stopwatch StartStop" $system
$time.Reset()
Start-Sleep 1
$time.Start()
Clear-Item Variable:a
$time.Stop()
$aTime = $time.Elapsed.TotalMilliseconds - $system
Write-Host "Clear-Item in " $aTime
$time.Reset()
Start-Sleep 1
$time.Start()
Remove-Variable b
$time.Stop()
$bTime = $time.Elapsed.TotalMilliseconds - $system
Write-Host "Remove-Variable in " $bTime
$time.Reset()
Start-Sleep 1
$time.Start()
Clear-Item Variable:c
$time.Stop()
$cTime = $time.Elapsed.TotalMilliseconds - $system
Write-Host "Clear-Item in " $cTime
$time.Reset()
Start-Sleep 1
$time.Start()
Remove-Variable d
$time.Stop()
$dTime = $time.Elapsed.TotalMilliseconds - $system
Write-Host "Remove-Variable in " $dTime
$time.Reset()
変数データ/コンテンツを確実にクリアすることができた唯一の方法は、以下を使用して現在のセッションで実行されているすべての変数を削除することです。
Remove-Variable -Name * -ErrorAction SilentlyContinue
これにより、すべての変数がすぐに削除されます。実際、これを一部のスクリプトの最後に追加しているので、同じ名前の可能性がある別のスクリプトを実行しても、新しいデータが追加されて、望ましくない結果が生じることはありません。
DRAWBACK: 1つの変数のみをクリアする必要がある場合(私の場合は数分前)、スクリプトに必要な入力変数を再インスタンス化する必要があります。
最も効率的な方法は、ガベージコレクションにその仕事をさせることです。 Powershellはすべて.NETであり、有名なメモリ管理機能を備えていることを忘れないでください。常にスコープを制御し、変数が不要になったらすぐにスコープから外れるようにします。たとえば、ループ内で一時変数が必要な場合、ループの最後で自動的に無効になるため、心配する必要はありません。
EDIT:アップデートに関しては、$yourPasswordVariable = $null
?ずっとわかりやすいと思います。そして、それはそれを行うための最速の方法でなければなりません。なぜならRemove-Item
およびClear-Item
は一種のオールインワンハンドラーであり、変数を本当に消去したいかどうかを判断する前に、まずいくつかのものを処理する必要があります。
どちらも、.NETオブジェクトへの「a」参照を効率的に削除します。これで、その参照がオブジェクトへの最後の参照である場合、GCはそのオブジェクトのメモリがいつ収集されるかを決定します。ただし、変数が不要になった場合は、Remove-Variable
を使用して、System.Management.Automation.PSVariable
オブジェクトに関連付けられたメモリも最終的に収集できるようにします。
スクリプトブロックとコマンドレットの実行にかかる時間を測定するには、Measure-Command
を使用します