tech.guitarrapc.cóm

Technical updates

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

先般にWMIオブジェクトの一覧や、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 3.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 &gt>he Official Scripting Guys Forum! >  >query with powershell: how to use forward only enumerators?</a>
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にして困ったことがないので…。 一度取得したデータを保持して、ネットワーク帯域への…などとも言いますが、過去はともかく現在ではどうでしょうか。 皆様各自でご判断ください。

参考サイト

今回は使いませんでしたが一応。