PowerShellはコマンドラインからワンライナーを実行させることができます。

これだけで、以下のように少し複雑なことも出来るのですが

コマンドライン経由なので、エスケープに対する配慮が必要で、面倒です。
例えばダブルクォーテーションをを含むスクリプトをPowerShellで扱いたい場合、以下のようになります。(PowerShellには「@(1,1,2,3,5,8,13) -join "`n`r"」という文字列が渡ることになります)

そういう制約から逃れる手段として、「ps1」形式のファイルを作成して実行するという方法がありますが

ps1という拡張子のファイルはデフォルト設定では実行できない設定になっています。

ただし、PowerShellの起動オプションで実行ポリシーを変更したセッションを用意すればps1ファイルも実行できますし、少し長くなりますがファイルを読み込んでテキストをスクリプトとして評価するメソッドに渡して実行させることもできます。
・・・というのを実際に動作確認したソースが以下。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<body> | |
</body> | |
<script> | |
AXO = function(name){return new ActiveXObject(name)} | |
shell = AXO('WScript.Shell') | |
fs = AXO('Scripting.FileSystemObject') | |
gsf2 = fs.GetSpecialFolder(2) | |
Read = function(p){var o=fs.OpenTextFile(p), s=o.AtEndOfStream?'':o.ReadAll(); o.Close(); return s} | |
Write = function(path,v){with(fs.CreateTextFile(path)){Write(v);return Close()}} | |
インデント調整=function(){ | |
var reg=/(\n[ \t]+)[^ \t]*$/, g='g', n='\n' | |
return function(str){ str+=''; return str.match(reg) ? str.replace(new RegExp(RegExp.$1,g), n) : str } | |
}() | |
com=function(){ | |
var reg0=/\/\*([^\v]*[^\r\n \t])[\r\n \t]*\*\//, reg1=/^[\r\n]*/g, L0='' | |
return function(fun){ return インデント調整((fun+'').match(reg0)[1]).replace(reg1,L0) } | |
}() | |
PowerShell={ | |
実行:function(cmd, op){ | |
var path=gsf2+'/'+(new Date()).getTime() | |
shell.run('cmd /C powershell '+(op||'')+' "'+cmd.replace(/"/g,'""')+'" > '+path, 0, true) | |
var ret='' | |
if(fs.FileExists(path)){ | |
ret = Read(path) | |
fs.DeleteFile(path) | |
} | |
return ret | |
}, | |
FolderBrowserDialog:function(defaultPath, rootPath, swNewFolderNG){ | |
var ret=this.実行(com(function(){/* | |
Add-Type -assemblyName System.Windows.Forms; | |
$d=new-object System.Windows.Forms.FolderBrowserDialog; | |
$d.ShowDialog(); | |
$d.SelectedPath; | |
*/}).replace(/[\r\n\t]/g,''), '-sta') | |
return ret | |
}, | |
ReadFile:function(path){ | |
var ret=this.実行(com(function(){/* | |
$file=new-object System.IO.StreamReader('-path-'); | |
$arr=@(); | |
while(($line = $file.ReadLine()) -ne $null){ $arr += $line }; | |
$file.Close(); | |
echo($arr -join "`n`r"") | |
*/}).replace(/[\r\n\t]/g,'').replace(/-path-/,path)) | |
return ret | |
}, | |
ReadEval:function(str){ | |
// コマンドライン経由ではエスケープでややこしくなるようなスクリプトを実行するためのメソッド。 | |
var path=gsf2+'/'+(new Date()).getTime() | |
Write(path, str) | |
var ret=this.実行(com(function(){/* | |
$file=new-object System.IO.StreamReader('-path-'); | |
$arr=@(); | |
while(($line = $file.ReadLine()) -ne $null){ $arr += $line }; | |
$file.Close(); | |
Invoke-Expression ($arr -join "`n`r"") # ←「`r」の後ろの「"」は1つで良いと思うが、実際に動かすと1つでは「終端記号無し」エラーになってしまう。 | |
*/}).replace(/[\r\n\t]/g,'').replace(/-path-/,path), '-sta') | |
fs.DeleteFile(path) | |
return ret | |
}, | |
FolderBrowserDialog:function(defaultPath, rootPath, swNewFolderNG){ | |
// https://msdn.microsoft.com/ja-jp/library/system.windows.forms.folderbrowserdialog(v=vs.110).aspx | |
// rootPathに入れられる値はEnvironment.SpecialFolder。任意のフォルダをルートとして表示することはできない。 | |
// https://msdn.microsoft.com/ja-jp/library/system.windows.forms.folderbrowserdialog.rootfolder(v=vs.110).aspx | |
// https://msdn.microsoft.com/ja-jp/library/system.environment.specialfolder(v=vs.110).aspx | |
// Environment.SpecialFolderについてはネットにいくつか情報があるが、自分の環境ではいずれも正常動作しなかった。 | |
// http://www.atmarkit.co.jp/fdotnet/dotnettips/056folderdlg/folderdlg.html | |
var code=com(function(){/* | |
Add-Type -assemblyName System.Windows.Forms; | |
$d=new-object System.Windows.Forms.FolderBrowserDialog; | |
-option- | |
$d.ShowDialog(); | |
$d.SelectedPath; | |
*/}).replace(/[\r\n\t]/g,'') | |
var arr=[] | |
if(defaultPath ){ arr.push('$d.SelectedPath = "'+defaultPath+'";') } | |
if( rootPath ){ arr.push('$d.RootFolder = Environment.SpecialFolder.'+rootPath+';') } | |
if(swNewFolderNG){ arr.push('$d.ShowNewFolderButton = $false;') } | |
code = code.replace(/-option-/, arr.join('\r\n').replace(/\//g,'\\')) // ←Pathが「/」区切りのままだと正常に動作しない。 | |
return this.ReadEval(code) | |
}, | |
ps1実行:function(pathPS1, op){ | |
// デフォルト状態ではps1ファイルは実行できない設定になっているが | |
// 起動オプションで実行ポリシーを変更したセッションを用意すれば実行できる。 | |
// http://qiita.com/tomoko523/items/df8e384d32a377381ef9 | |
var path=gsf2+'/'+(new Date()).getTime() | |
shell.run('cmd /C powershell '+(op||'')+' -NoProfile -ExecutionPolicy Unrestricted '+pathPS1+' > '+path, 0, true) | |
var ret='' | |
if(fs.FileExists(path)){ | |
ret = Read(path) | |
fs.DeleteFile(path) | |
} | |
return ret | |
}, | |
ps1CreateExec:function(str){ | |
// コマンドライン経由ではエスケープでややこしくなるようなスクリプトを実行するためのメソッド。 | |
var path=gsf2+'/'+(new Date()).getTime()+'.ps1' | |
Write(path, str) | |
var ret=this.ps1実行(path, '-sta') | |
fs.DeleteFile(path) | |
return ret | |
}, | |
FolderBrowserDialog:function(defaultPath, rootPath, swNewFolderNG){ | |
// https://msdn.microsoft.com/ja-jp/library/system.windows.forms.folderbrowserdialog(v=vs.110).aspx | |
// rootPathに入れられる値はEnvironment.SpecialFolder。任意のフォルダをルートとして表示することはできない。 | |
// https://msdn.microsoft.com/ja-jp/library/system.windows.forms.folderbrowserdialog.rootfolder(v=vs.110).aspx | |
// https://msdn.microsoft.com/ja-jp/library/system.environment.specialfolder(v=vs.110).aspx | |
// Environment.SpecialFolderについてはネットにいくつか情報があるが、自分の環境ではいずれも正常動作しなかった。 | |
// http://www.atmarkit.co.jp/fdotnet/dotnettips/056folderdlg/folderdlg.html | |
var code=com(function(){/* | |
Add-Type -assemblyName System.Windows.Forms; | |
$d=new-object System.Windows.Forms.FolderBrowserDialog; | |
-option- | |
$d.ShowDialog(); | |
$d.SelectedPath; | |
*/}).replace(/[\r\n\t]/g,'') | |
var arr=[] | |
if(defaultPath ){ arr.push('$d.SelectedPath = "'+defaultPath+'";') } | |
if( rootPath ){ arr.push('$d.RootFolder = Environment.SpecialFolder.'+rootPath+';') } | |
if(swNewFolderNG){ arr.push('$d.ShowNewFolderButton = $false;') } | |
code = code.replace(/-option-/, arr.join('\r\n').replace(/\//g,'\\')) // ←Pathが「/」区切りのままだと正常に動作しない。 | |
return this.ps1CreateExec(code) | |
} | |
} | |
switch(3){ | |
case 0: | |
document.body.innerText = PowerShell.FolderBrowserDialog() | |
break | |
case 1: | |
document.body.innerText = PowerShell.ReadFile('C/aaaaa.txt') | |
break | |
case 2: | |
document.body.innerText = PowerShell.ReadEval(com(function(){/* | |
Add-Type -assemblyName System.Windows.Forms; | |
$d=new-object System.Windows.Forms.FolderBrowserDialog; | |
$d.ShowDialog(); | |
$d.SelectedPath; | |
exit; # ←exitを入れないとHTA側のshell.runが終了待ちのまま固まってしまう。コマンドラインから実行する場合はなくても大丈夫。 | |
*/}).replace(/\t/g,'')) | |
break | |
case 3: | |
document.body.innerText = PowerShell.FolderBrowserDialog('', '') | |
break | |
} | |
</script> | |
</html> |
メソッドの名前が重複しているところがあるのは動作確認の名残です。
ソースを見てお気づきになるかもしれませんが、実行ポリシー変更セッションならps1ファイルを実行できるということを知ったのは動作確認の終盤でした。
ファイルを読んでスクリプトとして評価するサンプルも有っても良いと思い、今回の目的に対しては若干冗長な手法でしたが情報として残すことにしました。
Shell.Applicationに「BrowseForFolder」というメソッドがありますが、これではデフォルトが設定できません。。
返信削除http://www.haijin-boys.com/wiki/%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%E9%81%B8%E6%8A%9E%E3%83%80%E3%82%A4%E3%82%A2%E3%83%AD%E3%82%B0