uint64 の演算

by mcmug 9. 3月 2009 14:30

私のブログに書いていた記事を少し改訂して転載します

PowerShell version 1 では符号なし64ビット変数 uint64 間の演算を行おうとすると実行時にエラーになります。
ただし実際に大きな数値が演算子の両側にあるときのみです。
Uint64型の変数が演算対象であっても、格納されている値が 2147483647(16進数で7FFFFFFF)を超えていなければエラーは発生しません 。 

The operation '[System.UInt64] - [System.UInt64]' is not defined. 
演算 '[System.UInt64] - [System.UInt64]' は定義されていません。 
version 2 CTP3 ではそのような制限はなく演算可能となっています。たとえば次のような計算を行ってもエラーは発生しません。
PS > [uint64]$v1 = 2147483648 
PS > [uint64]$v2 = 2147483647 
PS > $v1 - $v2
Version 1 での対処方法は
  • 1bit 精度を失っても問題のない場合には、それぞれ2で割って引いて2倍する。
  • そもそも元の値がInt64の範囲を超えない保証があるならキャストして引き算する。 
  • Decimal構造体を使う。たとえば $GDiff = [Decimal]$G2 - [Decimal]$G1 のように。
などが考えられます。
演算速度や変数サイズなどを気にしないなら Decimal 構造体を使うのがよさそうです。 
 
Version 2 ではそのような考慮は不要になっています。
 
PowerShell のようなタイプのスクリプト言語は、
意識的に uint64 型の変数を使用している時以外にも、
何かシステムから取得した値が uint64 になっているという場合があるので注意が必要です。
簡単なテストでは実行時に小さな数値しか取得されず、
エラー発生の可能性に気づかないことがあるかもしれません。

最新のブログ

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

PowerShell | PowerShell V2 CTP3

Mutex サンプルコードの PowerShell 版

by mcmug 3. 3月 2009 16:00
MSDN のサンプルコードを PowerShell に書き換えてみようということで、
自分で使ってみたものから書いてみます。

まずは簡単ですが System.Threading.Mutex クラスのコンストラクタの
引数が (Boolean, String) のもの

http://msdn.microsoft.com/ja-jp/library/f55ddskf(VS.80).aspx 

に出ているものが元です。 
他の言語のものは public class Test とかで定義していますが、
PowerShell の場合それに相当する記述にあまり意味がなさそうな
気がするので、省略して単純に function Test で書いてみました。
中身の記述だけ参考になればということで。

# This example shows how a named mutex is used to signal between
# processes or threads. 
# Run this program from two (or more) command windows. Each process
# creates a Mutex object that represents the named mutex "MyMutex".
# The named mutex is a system object whose lifetime is bounded by the
# lifetimes of the Mutex objects that represent it. The named mutex
# is created when the first process creates its local Mutex; in this
# example, the named mutex is owned by the first process. The named 
# mutex is destroyed when all the Mutex objects that represent it
# have been released.
# The constructor overload shown here cannot tell the calling thread
# whether initial ownership of the named mutex was granted. Therefore,
# do not request initial ownership unless you are certain that the 
# thread will create the named mutex.
 
function Test
{
    # Create the named mutex. Only one system object named 
    # "MyMutex" can exist; the local Mutex object represents 
    # this system object, regardless of which process or thread
    # caused "MyMutex" to be created.
 
    $m = New-Object System.Threading.Mutex ($false, "MyMutex")
 
    # Try to gain control of the named mutex. If the mutex is 
    # controlled by another thread, wait for it to be released.        
    "Waiting for the Mutex." | Write-Host
    $ret = $m.WaitOne()
 
    # Keep control of the mutex until the user presses
    # ENTER.
    Read-Host -Prompt ("This application owns the mutex." +`
        "Press ENTER to release the mutex and exit.") 
 
    $m.ReleaseMutex()
}
 
. Test
 
Mutex クラスの説明のサンプルコードで
http://msdn.microsoft.com/ja-jp/library/system.threading.mutex(VS.80).aspx
に出ているものは Thread を使っているので PowerShell では単純に書けなくて、
(特に ThreadStart のところの書き換えとか)とりあえず断念。

自分自身が今やりたかったこともプロセス間のファイルアクセスの
排他制御だったので、とりあえず Thread は登場しないという理由もあります。(^_^;
 
そういえばPowerShell のファイルアクセス系のコマンドレットって
排他制御がどうなってるのかとか、読み込み系はリードオンリーでオープンされるのか、 
とか明記されてないですよね?
どこかに書いてありましたっけ。。。
 

最新のブログ

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

PowerShell

PCをスタンバイ状態にする方法

by mcmug 16. 2月 2009 12:55

PCをスタンバイ状態にするためのスクリプトを紹介しつつ助言を求めます。

使っているPCの1台をスタンバイ状態にしたい時があるのですが、
このPCはスタンバイ状態にしても、マウス(USB接続)が動くと起き上がってしまいます。
BIOS設定とかでそれを回避するようにしたいのですが方法がわからない状況です。

このPCにはキーボード・モニタ・マウス切替器がついています。
そして対象のPC以外に切り替えてしまえばマウスを動かしても起き上がらないので
そういう状態にしてしまえば問題はありません。
でも、スタートメニューなどから操作してスタンバイにしつつ、
切替器本体のスイッチを微妙なタイミングで押すというのは至難の業です(笑)
キーボードの切り替えホットキーというわけにもいきません。
その操作自体で起き上がったりしてわけがわからなくなります。

そこで、走らせてしばらくしてからスタンバイを行ってくれるスクリプトが欲しくなりました。

ところが、いろいろ調べたのですが、スタンバイ状態にするための方法がわかりません。
WMIとかいろいろみたのですが・・・
shutodown.exe にスタンバイオプションがあれば簡単なのに。

しかたがないのでシャットダウンダイアログを呼び出して
キーボードイベントを送るという方法を使っています。

何かもっとまともな良い手段はないものでしょうか。

 

 [void][Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
$wfs = [Windows.Forms.SendKeys]
[void][Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')
$vbi = [Microsoft.VisualBasic.Interaction]

$sh = New-Object -com Shell.Application
$sh.ShutdownWindows()
Start-Sleep 1
$vbi::AppActivate('Windows のシャットダウン')
Start-Sleep 10
$wfs::SendWait('{DOWN}{DOWN}{DOWN}{ENTER}')

 

最新のブログ

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

PowerShell

別プロセスの実行 / Invoke-WmiMethod の使い道の例

by mcmug 15. 2月 2009 00:56

PowerShell スクリプトの中から別のプロセスを実行するために V1 では次のように書いていました。

$w32c = [WMICLASS]"root\cimv2:Win32_Process"
$proc = $w32c.Create($cmd)

WMIクラスの名前を指定して取得し、そのメソッドを呼び出すという方法です。

V2 CTP3 では Invoke-WmiMethod コマンドレットが増えており、

Invoke-WmiMethod -class win32_process -name create -ArgumentList 'powershell.exe -window minimized'

のように書けます。こちらのほうがわかりやすいですね。root\cimv2 なんて覚えなくて済むにこしたことはないし。

Invoke-WmiMethod にはいろいろオプションがあるので、細かな制御もできそうです。

が、そのあたりはまだ試していないのでまた後日。

最新のブログ

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

PowerShell V2 CTP3

配列要素ごとの処理 ループとパイプライン

by mcmug 8. 2月 2009 15:34
配列に含まれる各要素に対して処理を行う場合の記述方法にはいくつかのバリエーションがあります。
(対象は配列に限りませんが・・・)

自分ではCやC++などの言語に慣れているので、
何も考えなければ for ループなどで書こうとするのですが、
パイプラインを使った方が簡潔に記述できる場合があります。

Foreach-Object に % という短く書ける alias が用意されているくらいですから、
PowerShell の作者にはパイプラインをどんどん使って欲しいという
意図もあるのかもしれません。

ここでは、例としてすべての要素に対して同じ処理を行うのではなく、先頭要素にのみ別の処理を行う場合を取り上げてみます。

入力として
'testad.example.co.jp'
のような文字列が変数 $adserver に与えられて、そこから
LDAP://testad/cn=Computers,DC=example,DC=net
という文字列を生成し変数 $tgtstr に格納する場合を例にとります。

私のようにパイプに慣れていない場合には、たとえば次のような記述が思い浮かびます。

$words = $adserver.split('.')
$tgtstr = "LDAP://{0}/cn=Computers" -f $words[0]
for ($idx = 1; $idx -lt $words.count; $idx++)
{
    $tgtstr += ",DC={0}" -f $words[$idx]
}

splitでピリオドを区切りとして分割された各単語要素は変数 $words に文字列配列として格納されます。先頭要素にインデックス0でアクセスして個別の処理を行い、1から最後までの$wordsの各要素にインデックス番号でアクセスしながら先頭とは別の共通処理を行います。これで動作としては問題ないのですが、インデックス用の変数 $idx を使うところが冗長に思えます。そこで、配列の先頭以外の要素をパイプラインに流して処理する方法を用いると次のように記述することができます。

$words = $adserver.split('.')
$tgtstr = "LDAP://{0}/cn=Computers" -f $words[0]
$words[1..($words.length - 1)] | % { $tgtstr += ",DC={0}" -f $_ }

パイプ記号 | の後ろの % は ForEach-Object コマンドレットの別名です。この例のように先頭要素を省くのではなく、先頭から指定個数要素のみを処理する場合や末尾から指定個数要素のみを処理する場合には、流す側の配列インデックスでの指定を行わなくとも、Select-Object の First および Last パラメターで指定することも可能です。

PS >1,2,3,4,5 | select -First 3 | % { Write-Host $_ }
1
2
3
PS>

また Where-Object を用いて何かの条件で対象を選別することも可能です。

PS >1,2,3,4,5,6 | where { $_ % 3 -eq 0 } | % { Write-Host $_ }
3
6
PS>

さらに分割した文字列要素を変数 $words にいったん格納することも避けるためには次のような記述も可能です。
$adserver.split('.') | % -begin {$tgtstr = ''} `
{
    if ($tgtstr -ne '') {$tgtstr += ",DC={0}" -f $_} 
    else {$tgtstr = "LDAP://{0}/cn=Computers" -f $_}
}

-begin で指定される ForEach-Object コマンドレットのパイプライン初期化時に実行されるスクリプトブロックにおいて出力用変数 $tgtstr の初期化を行います。それに続く、各要素ごとに実行されるスクリプトブロックの初回においては $tgtstr が空白なのでifによる判別で LDAP で始まる部分を生成する先頭要素固有の処理が実行され、それ以降は共通の処理が繰り返されることになります。

ただし最後の記述例とその前の記述例のどちらが望ましいかは、条件によって異なると考えられます。この例の場合であれば差がないでしょうが、大きなファイルからデータを読み込むような場合には、すべてメモリ上に読み終わってからそれ以降の処理が行われるか、逐次的に処理が行われるかの差が発生する場合があるのかな?

最新のブログ

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

PowerShell

Calendar

<<  3月 2010  >>
月曜火曜水曜木曜金曜土曜日曜
22232425262728
1234567
891011121314
15161718192021
22232425262728
2930311234

View posts in large calendar
Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010 PowerShell from Japan!!