tech.guitarrapc.cóm

Technical updates

PowerShellで、Get-WmiObjectにて「クォータ違反です」と怒られた場合のRewindableプロパティ変更による対応とWmi処理の処理速度向上

先般にWmiObjectの一覧や、Wmi継承元クラスの取得記事を書きました。 実はこの時も発生していましたが、Get-WmiObject を使用して大量のデータを取得するとクォータ違反ですというエラーが発生することがあります。
Get-WmiObject : クォータ違反です
発生場所 行:1 文字:1
+ Get-WmiObject -class meta_class | Select-Object Name
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Get-WmiObject]、ManagementException
    + FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
これは、Windows 2003やXPのみならず、Vista、7、Windows 8 x64 Pro環境でも変わらず発生しています。 また、PowerShell V3.0であっても発生します。 このクォータ違反は、既定では true になっているSystem.Management.EnumerationOptionsのRewindableプロパティをfalseにすることで回避できます。 また、RewindableプロパティをfalseにすることでWmiObjectのクエリパフォーマンスも向上しますのでご一考までに。 今回は、Rewindableの意図とプロパティの変更方法を紹介します。

System.Management.EnumerationOptions.Rewindableの役割

みんなの味方 MSDN 先生を参照してみます。
MSDN - EnumerationOptions クラス
Rewindableプロパティについては以下のように説明されています。
EnumerationOptions.Rewindable プロパティ コレクションが巻き戻し可能と見なされるかどうかを示す値を取得または設定します。 true の場合、コレクション内のオブジェクトは、複数回の列挙のために使用できます。 false の場合、そのコレクションは 1 回だけ列挙できます。
つまり以下です。
.NET Framework Class Library - EnumerationOptions.Rewindable Property If true, the objects in the collection will be kept available for multiple enumerations. If false, the collection can only be enumerated one time. A rewindable collection is more costly in memory consumption as all the objects need to be kept available at the same time. In a collection defined as non-rewindable, the objects are discarded after being returned in the enumeration.
そして、jrv (MCC, Partner)様の回答がここにあります。 本件とは関係なしに、Wmiのパフォーマンスについて論議されているので非常に有意義な内容になっています。
Script Center > Scripting Forums > The Official Scripting Guys Forum! > WMI query with powershell: how to use forward only enumerators? not sure but isn't $false the default. Async and semi-async queries cannnot be rewindable by default. Think about it. They are just spooling. Sync queries are slower but are there for when you need to reprocess the results repeatedly without having to requery for them again. This save the network - or so the lofic goes - and allows us to hold onto the results. I think under NET calsses the semi sync may be rewindable but I have never tried it. It was not in W2K WMI.
ということで、一度クエリしたWmiObject結果を再利用しない (Asyncで使うとか/随時取得する)場合は、Falseにするとメモリの節約、Wmiクエリパフォーマンスの大幅な向上が見込めます。 デフォルトでfalseにしてほしいものですが…。

System.Management.EnumerationOptions.Rewindableを$falseにしたい

至って簡単で、以下のコードを実行するだけです。 ※このプロパティはWmiセッション毎にデフォルトのTrueに変わるため、逐次実行が必要です。
$EnumerationOptions = New-Object System.Management.EnumerationOptions

#現在のRewindableの設定値を確認( default = true)
$EnumerationOptions.Rewindable

#Rewindableをfalseに設定
$EnumerationOptions.Rewindable = $false

#変更後のRewindableの設定値を確認( changed to = false )
$EnumerationOptions.Rewindable
結果からTrueからFalseに変更されている事が分かります。
True #デフォルト(変更前)
False #変更後
特に大量のデータを取得する時に、劇的に早くなった事が体感できるかと思います。 なお、一度、PowerShell ISEを閉じて、再度実行するとまたデフォルトに戻っている事が分かります。
$EnumerationOptions = New-Object System.Management.EnumerationOptions

#現在のRewindableの設定値を確認( default = true)
$EnumerationOptions.Rewindable

#Rewindableをfalseに設定
$EnumerationOptions.Rewindable = $false

#変更後のRewindableの設定値を確認( changed to = false )
$EnumerationOptions.Rewindable
またデフォルトに戻ってますね…。
True #デフォルト(変更前)
False #変更後

それでも大量に実行してるとエラーがでた

正直、Rewindableのfalse変更後には怒ったことがありません が、もしそれでも「クォータ違反です」出た場合は、Windows Management Instrumentation サービスを再起動することで保有メモリがリセットされるようです。
【PowerShell】特定のプロセス起動を監視したいですか?~Register-WMIEvent コマンドレット

まとめ

個人的には、基本System.Management.EnumerationOptions.Rewindableプロパティは$falseにして困ったことがないので…。 一度取得したデータを保持して、ネットワーク帯域への…などとも言いますが、過去はともかく現在ではどうでしょうか。 皆様各自でご判断ください。

参考サイト

[WMI] ManagementObjectSearher を使用して大量のデータを取得しようとすると クォータ違反です というエラーが発生する< How to connect to WMI using System.Management.ConnectionOptions for alternate credentials in powershell 今回は使いませんでしたが一応。 Memory and Handle Quotas in the WMI Provider Service