x64には存在しないScriptControlの代わり

以前、こんな記事を書いた。
x64には存在しないScriptControlの代わり - じゅんじゅんのきまぐれ
この時、ieのプロセスができちゃうなー、と思っていて、.Net JScriptの方法も書いたけど、ieのプロセスを作りたくなかったら、htmlfileを使えば良いことに今頃気づいたので、書いてみた。
ま、大して意味がないけど、Disposeしなくて良いのが利点か。
ただ、ie依存だと、x86とx64の橋渡しなんてこともできるんだよね。



スクリプト

これ、scriptをJScriptで書いてるからJScript版だけど、VBScriptで書けばVBScriptが動く、、、はず。

$js = New-Object PSObject
$js | Add-Member NoteProperty "hd" (New-Object -ComObject htmlfile)
$js.hd.IHTMLDocument2_write(@"
<html><head>
<meta http-equiv='X-UA-Compatible' content='IE=edge' />
<title>htmlfile for powershell</title>
<script>
document.__js = {
	eval: function(code, p) {
		var ret = null
		try {
			ret = eval(code)
		} catch(e) {
			this.lastErrNo = e.number
			this.lastErrMsg = e.description
			throw e
		}
		return ret;
	},
	get: function(obj, name) { return obj[name] },
	set: function(obj, name, val) { obj[name] = val },
	getAttrs: function(obj) {
		var ret = ''
		for(var a in obj) ret += ',' + a
		return ret.substr(1)
	},
	parse: function(str) { return JSON.parse(str) },
	stringify: function(obj, ind) { return JSON.stringify(obj, null, ind) }
}
</script>
</head><body></body></html>
"@)
$js | Add-Member NoteProperty "e" ([System.__ComObject].InvokeMember("__js", [System.Reflection.BindingFlags]::GetProperty, $null, $js.hd, $null))
$js | Add-Member ScriptMethod "Eval" {
	if($args.length -gt 0) {
		$para = $null
		if($args.length -gt 1) { $para = $args[1] }
		$this.e.eval($args[0], $para)
	}
}
$js | Add-Member ScriptMethod "Get" {
	$ret = $null
	if($args.length -gt 1) {
		$ns = $args[1]
		if($ns -isnot [Array]) { $ns = $ns -split '\.' }
		$len = $ns.Length
		$ret = $this.e.get($args[0], $ns[0])
		if($args.length -gt 2 -and $args[2] -and $ret -eq $null) {
			$ret = $this.e.eval("({})", $null)
			$this.e.set($args[0], $ns[0], $ret)
		}
		if($len -gt 1) { $ret = $this.Get($ret, $ns[1..($len-1)]) }
	}
	return $ret
}
$js | Add-Member ScriptMethod "Set" {
	if($args.length -gt 2) {
		$ns = $args[1]
		if($ns -isnot [Array]) { $ns = $ns -split '\.' }
		$len = $ns.Length
		if($len -gt 1) {
			$add = $true
			if($args.length -gt 3) { $add = $args[3] }
			$this.e.set($this.Get($args[0], $ns[0..($len-2)], $add), $ns[($len-1)], $args[2])
		} else {
			$this.e.set($args[0], $args[1], $args[2])
		}
	}
}
$js | Add-Member ScriptMethod "List" {
	$ret = @{}
	if($args.length -gt 0) {
		$tar = $args[0]
		if($args.length -gt 1) { $tar = $this.Get($tar, $args[1]) }
		$as = $this.e.getAttrs($tar) -split ","
		foreach($a in $as) {
			$val = $this.Get($tar, $a)
			#if($val -is [__ComObject]) { $val = $this.List($val) }
			$ret.Add($a, $val)
		}
	}
	return $ret
}
$js | Add-Member ScriptMethod "Run"{
	if($args.length -gt 1) {
		$obj = $null
		if($args.length -gt 2) { $obj = $args[2] }
		$ns = $args[1]
		if($ns -isnot [Array]) { $ns = $ns -split '\.' }
		$len = $ns.Length
		if($len -gt 1) {
			([System.__ComObject].InvokeMember($ns[($len-1)], [System.Reflection.BindingFlags]::InvokeMethod, $null, $this.Get($args[0], $ns[0..($len-2)]), $obj))
		} else {
			[System.__ComObject].InvokeMember($args[1], [System.Reflection.BindingFlags]::InvokeMethod, $null, $args[0], $obj)
		}
	}
}

詳しく、、、もないけどある程度は、
x64には存在しないScriptControlの代わり - じゅんじゅんのきまぐれ
を参照してください。

使用例

上のスクリプトを実行した後で、、、。
とりあえずスクリプトを実行したい場合

PS> $js.Eval('escape("ああん?")')
%u3042%u3042%u3093%uFF1F
PS> $js.Eval("unescape('%u3042%u3042%u3093%uFF1F')")
ああん?


実行の際、引数を渡したいなら

PS> $js.Eval('p * 3', 12)
36

第二引数がpとして参照できます。


JScriptオブジェクトを作るなら

PS> $jsobj = $js.e.parse('{"p1":12115,"p2":"testtest"}')
PS> $jsobj
System.__ComObject
PS> $js.e.stringify($jsobj, 2)
{
  "p1": 12115,
  "p2": "testtest"
}


作ったオブジェクトの要素一覧

PS> $js.List($jsobj)

Name                           Value
----                           -----
p1                             12115
p2                             testtest


オブジェクトの値を設定・取得したいなら

PS O:\> $js.Set($jsobj, 'p1', 12116)
PS O:\> $js.Get($jsobj, 'p1')
12116