PowerShell Memo

このサイトはPowerShell(MSH/Monad)奮闘記です

管理人「newpops吉岡洋」が
「PowerShell(旧名:MSH/Monad)」の研究結果を日々綴っていきます。

【お知らせ】
この日記からPowerShellのTipsを抽出し「PowerShell FAQ」として整理しました。


2005-11-30

[]オブジェクトの型を調べるコマンド

私は、Webでサンプルを見つける度に利用されているオブジェクトの型を調べる癖がついているのですが、(^^;

皆さんもオブジェクトの型を調べる機会は多くありませんか?

型を調べる(get-type)

型を調べる事はObjectの型を調べる - PowerShell Memoで紹介した通り簡単です。

ただ、毎回打ち込むのも面倒ですからコマンドを定義しておきましょう。


パスの通ったディレクトリに「get-type.msh」を置きます。

get-type.msh
# get-type.msh
param()

if($args[0] -ne $null)
{
    $args[0].gettype().fullname
}

「profile.msh」でエイリアスを登録するとさらに便利です。

profile.msh
alias gt get-type

使い方

プロセスの型を調べる
MSH C:\> gt (ps)
System.Object[]
MSH C:\> gt (ps)[0]
System.Diagnostics.Process
  • (ps)だとObject配列です
  • (ps)の要素は「System.Diagnostics.Process」です
Cmdletの型を調べる
MSH C:\> gt (get-command)[0]
System.Management.Automation.CmdletInfo
  • Cmdletの型は「System.Management.Automation.CmdletInfo」です

2005-11-29

[].NET2.0(RTM)用の「Monad Beta2」(3)

内部定義エイリアス

.NET2.0(RTM)用の「Monad Beta2」(2) - PowerShell Memoで書いた、内部定義エイリアスの一覧です。

MSH C:\> alias

CommandType     Name             Definition
-----------     ----             ----------
Alias           ac               add-content
Alias           clc              clear-content
Alias           cli              clear-item
Alias           clp              clear-property
Alias           clv              clear-variable
Alias           cpi              copy-item
Alias           cpp              copy-property
Alias           cvpa             convert-path
Alias           epal             export-alias
Alias           epcsv            export-csv
Alias           fc               format-custom
Alias           fl               format-list
Alias           foreach          foreach-object
Alias           ft               format-table
Alias           fw               format-wide
Alias           gal              get-alias
Alias           gc               get-content
Alias           gci              get-childitem
Alias           gcm              get-command
Alias           gdr              get-drive
Alias           ghy              get-history
Alias           gi               get-item
Alias           gl               get-location
Alias           gm               get-member
Alias           gp               get-property
Alias           gps              get-process
Alias           group            group-object
Alias           gsv              get-service
Alias           gu               get-unique
Alias           gv               get-variable
Alias           icm              invoke-command
Alias           ihy              invoke-history
Alias           ii               invoke-item
Alias           ilal             initialize-alias
Alias           ipal             import-alias
Alias           ipcsv            import-csv
Alias           mi               move-item
Alias           mp               move-property
Alias           nal              new-alias
Alias           ndr              new-drive
Alias           ni               new-item
Alias           nv               new-variable
Alias           oh               out-host
Alias           rdr              remove-drive
Alias           ri               remove-item
Alias           rni              rename-item
Alias           rnp              rename-property
Alias           rp               remove-property
Alias           rv               remove-variable
Alias           rvpa             resolve-path
Alias           sal              set-alias
Alias           sasv             start-service
Alias           sc               set-content
Alias           select           select-object
Alias           si               set-item
Alias           sl               set-location
Alias           sleep            start-sleep
Alias           sort             sort-object
Alias           sp               set-property
Alias           spps             stop-process
Alias           spsv             stop-service
Alias           sv               set-variable
Alias           where            where-object
Alias           cat              get-content
Alias           cd               set-location
Alias           clear            clear-host
Alias           cp               copy-item
Alias           h                get-history
Alias           history          get-history
Alias           kill             stop-process
Alias           lp               out-printer
Alias           ls               get-childitem
Alias           mount            new-drive
Alias           mv               move-item
Alias           popd             pop-location
Alias           ps               get-process
Alias           pushd            push-location
Alias           pwd              get-location
Alias           r                invoke-history
Alias           rm               remove-item
Alias           rmdir            remove-item
Alias           echo             write-object
Alias           cls              clear-host
Alias           chdir            set-location
Alias           copy             copy-item
Alias           del              remove-item
Alias           dir              get-childitem
Alias           erase            remove-item
Alias           move             move-item
Alias           rd               remove-item
Alias           ren              rename-item
Alias           set              set-variable
Alias           type             get-content

2005-11-28

[].NET2.0(RTM)用の「Monad Beta2」(2)

「set-alias」のエラー

.NET2.0Beta2用「Monad Beta2」から.NET2.0(RTM)用の「Monad Beta2」にアップグレードすると、

MSH起動時に以下のような「set-alias」のエラーが多数発生します。

set-alias : The AllScope option cannot be removed from the alias 'cat'.

At C:\Documents and Settings\All Users\Documents\msh\profile.msh:9 char:10

Monadは以下の「profile.msh」を起動時に読み込みますが、

  • 「<All Usersのマイドキュメント>\MSH\profile.msh」
  • 「<マイドキュメント>\MSH\profile.msh」

これらのファイルの「set-alias」の行がエラーとなってしまいます。


内部定義のエイリアス

この問題は、.NET2.0(RTM)用の「Monad Beta2」から「基本的なAliasを内部定義する」仕様に変更された事に起因します。


.NET2.0(RTM)用「Monad Beta2」では、「cat」「cd」などの基本的な「Alias」は、profile.mshが読み込まれる前に内部定義されます。そのため、「profie.msh」でAliasを再定義しようとするとAliasが上書きできずにエラーが発生するのです。

内部定義されるエイリアス

ac, clc, cli, clp, clv, cpi, cpp, cvpa, epal, epcsv

fc, fl, foreach, ft, fw, gal, gc, gci, gcm, gdr

ghy, gi, gl, gm, gp, gps, group, gsv, gu, gv

icm, ihy, ii, ilal, ipal, ipcsv, mi, mp, nal, ndr

ni, nv, oh, rdr, ri, rni, rnp, rp, rv, rvpa

sal, sasv, sc, select, si, sl, sleep, sort, sp, spps

spsv, sv, where, cat, cd, clear, cp, h, history, kill

lp, ls, mount, mv, popd, ps, pushd, pwd, r, rm

rmdir, echo, cls, chdir, copy, del, dir, erase, move, rd

ren, set, type

エラーの回避方法は2つ。

  1. 「profile.msh」のファイル上からset-aliasの二重定義を削除する
  2. 「profile.msh」でエイリアスを削除してから再定義する

1が良いでしょう。



2を実践する場合は以下のように入力します。

エイリアス削除の例
MSH C:\> remove-item alias:cat -force
MSH C:\> set-alias cat  get-content

「set-location」のスコープ

「set-alias」の「-Option」オプションではエイリアスのスコープを定義します。

.NET2.0(RTM)用「Monad Beta2」ではスコープに「None」と「AllScope」が追加されているようです。

#内部定義エイリアスのスコープは「AllScope」です。


エイリアスのスコープ
  • None(.NET2.0(RTM)用「Monad Beta2」から追加)
  • ReadOnly
  • Constant
  • Private
  • AllScope(.NET2.0(RTM)用「Monad Beta2」から追加)

#Noneはどのような挙動なのでしょうか?

2005-11-27

[]入力されたキーを取得する

「System.Console」クラスの:「Readkey」メソッドを利用すると入力されたキーの取得が可能です。

「ReadKey」によるキーの取得

小文字「t」を入力した場合
MSH C:\> $key = [System.Console]::Readkey()
tMSH C:\> $key.getType().FullName
System.ConsoleKeyInfo
MSH C:\> $key

  KeyChar   Key   Modifiers
  -------   ---   ---------
        t     T           0
  • 結果は「System.ConsoleKeyInfo」クラスに取得されます。
大文字「t」を入力した場合
MSH C:\> $key = [System.Console]::Readkey()
TMSH C:\> $key

  KeyChar   Key   Modifiers
  -------   ---   ---------
        T     T       Shift
  • Shiftキーが押されたことが分かります。

2005-11-26

[]「String.Format」に相当する「-F」オプション

MSHでは、.NETのFormat関数に相当する「-F」オプションが用意されています。

文字列のフォーマット変換:「String.Format」

.NET Frameworkの「String.Format」を利用すると文字列をフォーマット変換できます。

数値の3桁表示(「String.Format」)
MSH C:\> 1..10 | foreach {[String]::Format("{0:000}",$_)}
001
002
003
004
005
006
007
008
009
010

文字列のフォーマット変換:「-F」オプション

「String.Format」をMSHから簡単に利用できるのが「-F」オプションです。

以下のように利用します。

数値の3桁表示(「-F」オプション)
MSH C:\> 1..10 | foreach {"{0:000}" -F $_}
001
002
003
004
005
006
007
008
009
010
「プロセス名」と「ページングされるメモリのサイズ」を表示する
MSH C:\> ps | foreach {"{0,-15} {1,15:#,###}" -F $_.Name , $_.PagedMemorySize}
BsCLiP                2,408,448
CCAPP                26,615,808
CCEVTMGR              4,640,768
CCPROXY               5,681,152
CCSETMGR              7,688,192
clnch                 2,195,456
conime                1,187,840
CSRSS                 1,687,552
CTFMON                1,466,368
cvslock                 475,136
cvsservice            1,024,000
emeditor              3,399,680
emedtray              1,085,440
explorer              7,196,672
fpdisp4               1,900,544
hidserv                 438,272
Husen                 3,297,280
Idle
IEXPLORE             50,249,728
(中略)

書式指定は型の書式設定を参照して下さい。

2005-11-25

[]Microsoft Developers Conference 2006

「MDC2006」・・・と呼べば良いのかな?

2006/02/02〜2006/02/03にパシフィコ横浜で「no title」が開かれます。

このカンファレンスの位置付けは

まだ発売されていない次世代製品、技術にフォーカスした開発者向けテクニカル コンファレンス

だそうで、もちろんWinFX関連の基調講演/セッションも数多く予定されています。

Monadのセッションはこちら。

T2-310 Monad : 最新コマンドライン スクリプティング

2005-11-24

[]MonadからVB.NETのコードを実行(2)

MonadからVB.NETのコードを実行 - PowerShell Memoでは、

例えば、Beta2のMonadではSTAスレッドで実行が必要なオブジェクトは動作しませんが、

VBCodeProviderを利用してVB.NETのコードを書けば、実現できるわけです。

と書きましたが、その具体例を紹介します。


System.Windows.Forms.ClipboardはSTAスレッドで実行が必要なため、Clipboardを利用してクリップボードにはアクセスできません。

参考:404 Not Found


その解決方法としてNewsGroupで「VBCodeProviderを利用してクリップボードへアクセスするサンプル」が紹介されています。

We are sorry, the page you requested cannot be found


$provider = new-object Microsoft.VisualBasic.VBCodeProvider 
$params = new-object System.CodeDom.Compiler.CompilerParameters 
$params.GenerateInMemory = $True 
$refs = 
"System.dll","Microsoft.VisualBasic.dll","System.Data.DLL", `
"System.management.dll","System.DirectoryServices.dll" 
$params.ReferencedAssemblies.AddRange($refs) 

# VB.NET EXAMPLE 
$txtCode = @' 

Imports Microsoft.VisualBasic 
Imports System 
Imports System.Threading 

Public Class mow 

Sub Main() 
Dim newThread As Thread = New Thread(AddressOf ThreadMethod) 
newThread.ApartmentState = ApartmentState.STA 
newThread.Start() 
End Sub 

Shared Sub ThreadMethod() 
dim Comp as new Microsoft.VisualBasic.Devices.computer 
comp.clipboard.setText("hello Clip") 
End Sub 

End Class 


'@ 

$results = $provider.CompileAssemblyFromSource($params, $txtCode) 
$mAssembly = $results.CompiledAssembly 
$i = $mAssembly.CreateInstance("mow") 
$r = $i.main() 

また、上記サンプル作者のページでは、ClipboardクラスをSTAスレッドで利用するようにラップしたDLLを通して、MSHからクリップボードを操作する方法も紹介されています。

/¥/¥o¥/¥/ PowerShelled: MSH Clipboard part 2 (of 3 ?)

2005-11-23

[]MonadからVB.NETのコードを実行

VBCodeProviderを利用すると、VB.NETのコードをMonadから実行できます。

例えば、Beta2のMonadではSTAスレッドで実行が必要なオブジェクトは動作しませんが、

VBCodeProviderを利用してVB.NETのコードを書けば、実現できるわけです。


インコードコンパイルでMsgBox関数を実行する

以下は、MsgBoxを実行するサンプルです。

$provider = new-object Microsoft.VisualBasic.VBCodeProvider
$params = new-object System.CodeDom.Compiler.CompilerParameters
$params.GenerateInMemory = $True
$refs = "System.dll","Microsoft.VisualBasic.dll","System.Data.DLL", `
"System.management.dll","System.DirectoryServices.dll"
$params.ReferencedAssemblies.AddRange($refs)

# VB.NET EXAMPLE
$txtCode = @'

Imports Microsoft.VisualBasic
Imports System
Imports System.Threading

Public Class VBDotNetTest
     Sub Main()
        MsgBox("MonadからVB.NETのコードを実行", 0, "タイトル")
     End Sub
End Class

'@

$results = $provider.CompileAssemblyFromSource($params, $txtCode)
$mAssembly = $results.CompiledAssembly
$i = $mAssembly.CreateInstance("VBDotNetTest")
$r = $i.main()

2005-11-22

[].NET2.0(RTM)用の「Monad Beta2」

TechNet Magazine NOVEMBER・DECEMBER 2005 - PowerShell Memoで触れた「TechNet Magazine」でも書かれていますが、.NET2.0(RTM)用の「Monad Beta2」が公開されています。

.NET2.0Beta2用「Monad Beta2」からの変更点として、スクリプト実行ポリシーが変更になっています。


.NET2.0Beta2用「Monad Beta2」では、実行ポリシーは以下の3つでした。

.NET2.0(RTM)用の「Monad Beta2」では、「Restricted」が追加され、デフォルトとなっています。


実行ポリシー、署名については、まだ調査中だったのですが、

タイムリーに、oka326さんのブログで詳細な解説が発表されたので、

詳細はoka326さんの記事を参照してください。(^^;


Random thoughts on my interest

2005-11-21

[]TechNet Magazine NOVEMBER・DECEMBER 2005

Monadのコラム

TechNet MagazineのコラムでMonadが詳しく紹介されています。

Monad: The Future of Windows Scripting


コラム作者(Thomas Lee)の「profile.msh」が以下からダウンロードできますが、

head、tail、touchを始め、便利な関数が記述されているため必見です。


Download:Scripting.exe

2005-11-20

[]Monadの管理者ガイドが近日発売

Msh: an Administrator's Guide: An Administrator's Guide

来月上旬発売です。

Monad: Introducing the Msh Command Shell and Language

Monad: Introducing the Msh Command Shell and Language

さっそく予約しました。

2005-11-19

[]$hostの謎

$hostは現在実行中のホスト情報を格納しています。

「$host」の型は何?

MSH C:\> $host.gettype()

IsPublic IsSerial Name          BaseType
-------- -------- ----          --------
False    False    InternalHost  System.Management.Automation.Host.MshHost


MSH C:\> $host.gettype().fullname
System.Management.Automation.Internal.Host.InternalHost
  • 型:「System.Management.Automation.Host.MshHost」
  • インスタンス名:InternalHost

$hostは、「System.Management.Automation.Host.MshHost」ということになります。


では、InternalHostの1階層上の部分、

System.Management.Automation.Internal.HostMSDNにも載っていませんが、何者なのでしょうか。

2005-11-18

[]A Monad Video Game

インベーダーゲーム

Precision Computingで、Monadで作成されたインベーダーゲームが紹介されています。

2005-11-17

[]文字色、背景色を設定する

「write-host」の文字色、背景色を設定する

write-host [object] [-ForegroundColor foregroundColor] [-BackgroundColor backGroundColor]

「foregroundColor」「backGroundColor」で文字色、背景色を指定します。

設定可能な色は「ConsoleColor Enumeration」で定義されています。

参照:ConsoleColor Enumeration

  • Black
  • Blue
  • Cyan
  • DarkBlue
  • DarkCyan
  • DarkGray
  • DarkGreen
  • DarkMagenta
  • DarkRed
  • DarkYellow
  • Gray
  • Green
  • Magenta
  • Red
  • White
  • Yellow
「write-host」の文字色、背景色設定サンプル
Write-Host aaa -ForeGroundColor Red -BackGroundColor Green

「コンソール」の文字色、背景色を設定する

「コンソール」の文字色、背景色を設定するには、

  • $host.ui.rawui.foregroundcolor
  • $host.ui.rawui.backgroundcolor

を利用します。

「コンソール」の文字色、背景色設定サンプル
#文字色設定
$host.ui.rawui.foregroundcolor = "DarkYellow"
#背景色設定
$host.ui.rawui.backgroundcolor = "Blue"

2005-11-16

[]文字列操作(3)

一月以上ぶりに、文字列操作の基本構文。


文字列操作色々〜その3〜

文字列の右側を指定文字列で埋める
MSH C:\> "[" + "365".PadRight(10, " ") + "]"
[365       ]
MSH C:\> "[" + "123345".PadRight(10, " ")  + "]"
[123345    ]

文字列の左側を指定文字列で埋める
MSH C:\> "[" + "365".PadLeft(10, " ") + "]"
[       365]
MSH C:\> "[" + "12345".PadLeft(10, " ") + "]"
[     12345]
文字列の一部を削除する
MSH C:\> $a = "0123456789"
MSH C:\> $a.Remove(4,2)
01236789
文字列を置換する
MSH C:\> $a = "newpops"
MSH C:\> $a.Replace("new","old")
oldpops
文字列をChar配列に変換する
MSH C:\> $a = "newpops"
MSH C:\> $a.ToCharArray()
n
e
w
p
o
p
s
指定文字列でトリムする
MSH C:\> $a = "#########MSH Memo#########"
MSH C:\> $a.Trim("#")
MSH Memo
MSH C:\> $a.TrimStart("#")
MSH Memo#########
MSH C:\> $a.TrimEnd("#")
#########MSH Memo

2005-11-15

[]オブジェクトHTMLに変換する(convert-html)

※「convert-html」はPowerShell 1.0では「ConvertTo-Html」という名前に変更されています。

「convert-html」:オブジェクトHTMLに変換する

構文

convert-html -Property] object[? [-InputObject MshObject] [-Body bodyText] [-Head headText] [-Title titleText]

文字列をIEに出力する(out-ie) - PowerShell Memoで紹介した「out-ie」と組み合わせると便利です。

「System.DateTime」をHTMLテーブル表示
$ie = convert-html -InputObject (get-date) | out-ie
「wで始まるプロセスの情報」をHTMLテーブル表示
$ie = ps w* | convert-html -Title "W* Process"| out-ie
  • 「-Title」でタイトルを指定できます。
  • 「System.Diagnostics.Process」の情報をHTMLテーブル表示します。
「wで始まるプロセスオブジェクト配列」をHTMLテーブル表示
$ie = convert-html -inputobject (ps w*) | out-ie
  • 「System.Object[]」の情報をHTMLテーブル表示します。

テーブルにボーダーを付ける

function set-border()
{
    param([String]$table)
    $table = $table -replace "<table>","<table border='1'>"
    $table = $table -replace "<td></td>","<td><br></td>" 
    $table
}
$ie = ps | convert-html | foreach {set-border($_)} | out-ie
  • TDタグの間にBRタグを入れることで、値が空のセルもボーダーを潰さないようにしています。

2005-11-14

[]文字列をIEに出力する(out-ie)

またまたPDC2005ネタです。

MonadとVBScript(IE)の連携デモ(mms://media.sitestream.com/microsoft_sitestream_com/open/PDC05/TLN/TLN303/0MM7.wmv)の中で、

「out-ie」というコマンドが利用されています。


標準では用意されていないCmdletなので、なんだろな〜と思っていたのですが、注意深くムービーを見ると、「out-ie.msh」というファイルが一瞬だけ映っていました。デモ用に用意したスクリプトのようですね。


ということで、今回は、ムービーの挙動から予想して「out-ie」コマンドを作成してみました。

「convert-html」Cmdletの出力結果をIEに出力するなど、結構、便利です。


ムービーから予想される「out-ie」の仕様

追加仕様

  • パイプで文字列配列を渡した際は、全ての要素をIEに出力するようにしました。

「out-ie

※MSHのインストールパス($MSHHOME)に置いてください。

out-ie.msh
param()

#パイプでオブジェクトが渡されたかチェック
$test = $input.clone()
if($test.MoveNext() -eq $False){return}

#パイプで渡されたのが「文字列」かどうかチェック
$html = @($input)
if(($html[0] -is [System.String]) -eq $False){}

$ie = new-object -com internetexplorer.application
$ie.visible = $true
[void]$ie.navigate2("about:blank")

while($ie.ReadyState -ne 4){}

for($i=0; $i -lt $html.length; $i++)
{
    [void]$ie.document.writeln([String]$html[$i])
}
[void]$ie.refresh()
return $ie

実行方法

実行例

get-date | convert-HTML | out-ie

2005-11-13

[]Monad + VBScript(IE)のサンプル

Monad + VBScript(IE) - PowerShell Memoで紹介した「MonadとVBScript(IE)の連携デモ」のスクリプトは、

「MSH Script」と「HTML(withVBScript)」が1つのファイルに詰め込まれているので、メンテナンス性がよくありません。

そこで、少し改修してみました。


  • 変更点
    • Viewである「HTML(withVBScript)」を別ファイルに切り出し
    • エラーチェックを強化

サンプル

chart.msh
param($name, $value, $title = "Chart created by Monad")

#パイプでオブジェクトが渡されたかチェック
$test = $input.clone()
if($test.MoveNext() -eq $False){return}

#パイプで渡されたのが「プロセスオブジェクトの配列」かどうかチェック
$processs = @($input)
if(($processs[0] -is [System.Diagnostics.Process]) -eq $False){return}

#スクリプトのパスを取得
$scriptDir = parse-path $MyInvocation.MyCommand.Path -parent

#テンプレートスクリプトの実行(関数のインクルード)
$templateScriptPath = combine-path $scriptDir "chartHTML.msh"
. $templateScriptPath

#プロセスの名前を取得
$Names = '"' + [string]::Join('","', ($processs | foreach {$_.$name})) + '"'
#プロセスのプロパティを取得
$Values = '"' + [string]::Join('","', ($processs | foreach {$_.$value})) + '"'

#HTML出力
outChart $title $value $Names $Values
chartHTML.msh
function outChart()
{
    param([String]$title, [String]$value, [String]$Names, [String]$Values)
@"
<html>
<head>
<title>$title</title>
</head>
<BODY>
<object id=ChartSpace1 classid="CLSID:0002E55D-0000-0000-C000-000000000046">
</object>
<script language="VBScript">
option explicit
Sub window_onload()
Dim oChart
Dim oSeries1
Dim oConst
ChartSpace1.Clear
Set oConst = ChartSpace1.Constants
Set oChart = ChartSpace1.Charts.Add

Set oSeries1= oChart.SeriesCollection.Add
with oSeries1
    .Caption = "$value"
    .SetData oConst.chDimCategories, oConst.chDataLiteral, Array($Names)
    .SetData oConst.chDimValues, oConst.chDataLiteral, Array($Values)
    .DataLabelsCollection.Add
    .Type = 0
End with

oChart.HasLegend = True
oChart.HasTitle  = True
oChart.Title.Caption = "$title"
End Sub
</script>
</body>
</html>
"@
}

実行方法


実行例

ps | .\chart name handlecount >result.html

ps | .\chart name PagedMemorySize >result.html


2005-11-12

[]「head」と「tail」

UNIXシェルの「head」と「tail」を作成してみます。


「head」(読み込み行数のデフォルト:10)

function Get-Head
{
    PARAM([String]$file, [int]$line=10)
    get-content $file | select-object -first $line
}
set-Alias head Get-Head
「head」利用例
MSH C:\..\Microsoft Command Shell>head about_Alias.help.txt 5
TOPIC
    Aliases

SHORT DESCRIPTION
    Using pseudonyms to refer to Cmdlet names in the Microsoft Shell
MSH C:\..\Microsoft Command Shell> head about_Alias.help.txt
TOPIC
    Aliases

SHORT DESCRIPTION
    Using pseudonyms to refer to Cmdlet names in the Microsoft Shell
    (MSH)

LONG DESCRIPTION
    An alias is a pseudonym, or "nickname," that you can assign to a
    Cmdlet so that you can use the alias in place of the Cmdlet name.

「tail」(読み込み行数のデフォルト:10)

function Get-Tail
{
    PARAM([String]$file, [int]$line=10)
    get-content $file | select-object -last $line
}
set-Alias tail get-tail
「tail」利用例
MSH C:\..\Microsoft Command Shell>tail about_Alias.help.txt 3

        help lang_variable

MSH C:\..\Microsoft Command Shell> tail about_Alias.help.txt
        help conc_profile.msh

    For information about functions, enter the following command:

        help lang_function

    For information about variables, enter the following command:

        help lang_variable

2005-11-11

[]パスの結合(combine-path)

※「combine-path」はPowerShell 1.0では「Join-Path」という名前に変更されています。

「combine-path」はパスの結合を行うCmdletです。

パスは、ファイル/レジストリの両方に対応可能です。

「combine-path」:ファイルパスの結合

「\」がなくても補完してくれます
MSH C:\> combine-path D: Doc
D:\Doc
MSH C:\> combine-path D:\ Doc\MSH
D:\Doc\MSH
MSH C:\> combine-path D:\ \Doc\MSH
D:\Doc\MSH

「combine-path」:ファイルパスの結合(パスの存在チェック付き)

「-resolve」でパスの存在チェック
MSH C:\> combine-path D:\ \Doc\MSH2 -resolve
combine-path : Cannot find path 'D:\Doc\MSH2' because it does not exist.
At line:1 char:13
+ combine-path  <<<< D:\ \Doc\MSH2 -resolve

「combine-path」:レジストリパスの結合

「\」がなくても補完してくれます
MSH C:\> combine-path HKLM:\ Software
HKLM:\Software
MSH C:\> combine-path HKLM:\ \Software
HKLM:\Software

「combine-path」:レジストリパスの結合(パスの存在チェック付き)

「-resolve」でパスの存在チェック
MSH C:\> combine-path HKLM:\ \Software -resolve
HKLM:\Software
MSH C:\> combine-path HKLM:\ \Software2 -resolve
combine-path : Cannot find path 'HKLM:\Software2' because it does not exist.
At line:1 char:13
+ combine-path  <<<< HKLM:\ \Software2 -resolve

2005-11-10

[]スクリプト自身のパスを取得する

$MyInvocation

「$MyInvocation」はスクリプト実行時、スクリプト自身の情報を格納しています。

スクリプト自身のパスは、

$MyInvocation.MyCommand.Path

スクリプト名は、

$MyInvocation.MyCommand.Name

に格納されています。



では、サンプルです。

まず、以下の3つのスクリプトを用意します。

C:\TestA\a.msh
Write-Host '【a.msh】'
Write-Host $MyInvocation.MyCommand.Path
Write-Host $MyInvocation.MyCommand.Name
Write-Host (parse-path $MyInvocation.MyCommand.Path -parent)
C:\TestB\b.msh
Write-Host '【b.msh】'
Write-Host $MyInvocation.MyCommand.Path
Write-Host $MyInvocation.MyCommand.Name
Write-Host (parse-path $MyInvocation.MyCommand.Path -parent)
C:\TestC\c.msh
Write-Host '【c.msh】'
Write-Host $MyInvocation.MyCommand.Path
Write-Host $MyInvocation.MyCommand.Name
Write-Host (parse-path $MyInvocation.MyCommand.Path -parent)

次に、以下を実行してみます。

MSH C:\> .\TestA\a.msh | .\TestB\b.msh | .\TestC\c.msh
【a.msh】
C:\TestA\a.msh
a.msh
C:\TestA
【b.msh】
C:\TestB\b.msh
b.msh
C:\TestB
【c.msh】
C:\TestC\c.msh
c.msh
C:\TestC

が取得できました。

2005-11-09

[]スクリプトファイルのインクルード

汎用的な処理を1つのスクリプトにまとめ、他のスクリプトから利用したい場合、

スクリプトファイルのインクルードができれば便利です。


「.(ドット)」+「 (スペース)」でインクルード

「.(ドット)」+「 (スペース)」に続けてスクリプトファイルを指定すると、

そのスクリプトファイルが実行され、定義されている関数を利用できるようになります。


より正確に言うと、「.(ドット)」+「 (スペース)」+「スクリプト」を実行すると、

指定した「スクリプト」の内容が、呼び出し元スクリプトに展開されるため、

スクリプト」で定義されたfunctionが呼び出し元スクリプトで利用可能になる訳です。


ちなみに、「.(ドット)」+「 (スペース)」なしで「スクリプト」を実行しても、

スクリプト」の内容は展開されないため、定義されている関数を呼び出すことはできません。

インクルードのサンプル

include.mshの内容確認
MSH C:\> get-content .\include.msh
function header()
{
@"
<html>
<head>
<title>$title</title>
</head>
"@
}
インクルード前は「header」関数は実行不可
MSH C:\> header
'header' is not recognized as a Cmdlet, function, operable program, or script file.
At line:1 char:6
+ header <<<<
「.(ドット)」+「 (スペース)」でインクルード
MSH C:\> . .\include.msh
「header」関数の呼び出しが可能
MSH C:\> header
<html>
<head>
<title></title>
</head>
変数を設定すると・・・
MSH C:\> $title = "MSH Memo"
MSH C:\> header
<html>
<head>
<title>MSH Memo</title>
</head>

2005-11-08

[]プロパティフィルタリング

「filter」プロパティフィルタリング

「filter」ステートメント(という表現で正しいのかな?)を利用すると、プロパティフィルタリングできます。


ヘルプは、以下のスクリプトで確認できます。

help about_Filter

指定プロパティ名でフィルタリング

以下を定義しておくと、

filter pick($property)
{
    $_.$property
}

以下のように指定プロパティ名でフィルタリングできます。

MSH C:\> ps | pick name
calc
CCAPP
(中略)

「select-object」と「filter」の違い

オブジェクトのフィルタリング(select-object) - PowerShell Memoで紹介した「select-object」との違いは?


「select-object」はフィルタしたプロパティがコレクションの時に展開しませんが、

「filter」はフィルタしたプロパティがコレクションの時に展開します。


以下に例を示します。

「select-object」はコレクションを展開しない
MSH C:\> get-command | select ParameterSets

ParameterSets
-------------
{__AllParameterSets}
{__AllParameterSets}
{__AllParameterSets}
(省略)

「filter」はコレクションを展開する
MSH C:\> get-command | pick ParameterSets

Parameter Set Name: __AllParameterSets
Is default parameter set: False

  Parameter Name: Value
    Type = System.Object[]
    Position = 1
    IsMandatory = True
    HelpMessage =
    ValueFromPipeline = True
    ValueFromPipelineByPropertyName = True
    ValueFromRemainingArguments = False
    Aliases = {}
    Attributes =
      System.Management.Automation.ParameterAttribute
      System.Management.Automation.AllowNullAttribute
      System.Management.Automation.AllowEmptyCollectionAttribute

  Parameter Name: PassThru
    Type = System.Boolean
    Position = -2147483648
    IsMandatory = False
    HelpMessage =
    ValueFromPipeline = False
    ValueFromPipelineByPropertyName = False
    ValueFromRemainingArguments = False
    Aliases = {}
    Attributes =
      System.Management.Automation.ParameterAttribute
(省略)

2005-11-07

[]終了したプロセスを知る

「get-process」はCmdlet実行時のスナップショット

「get-process」で取得できるプロセス情報は、Cmdlet実行時のスナップショットです。

あるプロセスが生きているかをチェックする際、

もちろん、毎回「get-process」を発行すれば確認は可能ですが、それではコストがかかりすぎます。


今回紹介する方法を使うと、毎回「get-process」を発行することなく、

「指定プロセスが終了したかどうか」をチェックすることが可能になります。

「HasExited」プロパティ

「プロセスが終了したかどうか」を判定するには、

「get-process」で取得できる「System.Diagnostics.Process」オブジェクトの「HasExited」プロパティを利用します。

参考:HasExited Property


「HasExited」プロパティは、

  • プロセスが終了していれば「True」
  • プロセスが生きていれば「False」

を返します。


終了したプロセスを取得する

最初に「メモ帳」と「電卓」を起動し、プロセス一覧を取得します。

MSH C:\> notepad
MSH C:\> calc
MSH C:\> $process = get-process

次に「メモ帳」と「電卓」の「×」ボタンを押してプロセスを終了してから、

以下のスクリプトを実行してみましょう。

MSH C:\> $process | where {$_.hasexited}

Handles  NPM(K)    PM(K)      WS(K) VS(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
     62       4     1180       3856    25            2828 calc
     66       4     1212       3812    25            1940 notepad

メモ帳」と「電卓」のプロセスが終了した事が分かります。

2005-11-06

[]HereString

「HereString」は改行やタブ、引用符を文字列として含めることができます。

変数展開あり/なしの2種類のタイプがあります。

HereString(変数展開あり)

@"[文字列]"@

HTMLヘッダ出力
MSH C:\> $title = "MSH Memo"
MSH C:\> @"
>> <html>
>> <head>
>> <title>$title</title>
>> </head>
>> "@
>>
<html>
<head>
<title>MSH Memo</title>
</head>

HereString(変数展開なし)

@'文字列'@

サンプル:文字列展開なし
MSH C:\> $word = "Hello Monad!"
MSH C:\> @'
>> ###################
>> $word
>> ###################
>> '@
>>
###################
$word
###################

2005-11-05

[]STAスレッドで実行が必要なオブジェクトが動作しない問題

現バージョンのMSHでは、STAスレッドで実行が必要なオブジェクトが動作しません。

例えば、.NET2.0で追加されたWebBrowserコントロールもその1つです。


ニュースグループmicrosoft.public.windows.server.scripting

に書かれていましたが、これは、Monad開発チームは既知の問題として捉えており、対応予定だそうです。

2005-11-04

[]Monad + VBScript(IE)

PDC 2005 Demo Video - PowerShell Memoで紹介したPDC 2005のDemo VideoにMonadとVBScript(IE)の連携デモがあります。


HTML(withVBScript)を出力するFunctionをMSH Scriptで記述し、

出力したHTML上のVBScriptからExcelのChartオブジェクトを生成/表示する、

というもの。


以下のMovieの3:12くらいから見れます。

mms://media.sitestream.com/microsoft_sitestream_com/open/PDC05/TLN/TLN303/0MM7.wmv


MVC

という使い分けですね。VをHTAにしても面白いでしょう。

MonadのCOM制限をカバー

確かに、この組み合わせは便利です。

Monad Beta2ではCOM呼び出しに制限がありますが(COMスクリプティングが貧弱 - PowerShell Memo参照)、

COM操作をVBScriptに任せてしまえば、Monadの制限をカバーできます。

2005-11-03

[]PDC 2005 Demo Video

Monad Advanced Command Line ScriptingにPDC2005で行われたMonadのDemo Movieが公開されています。

#使用されたPowerPoint資料もダウンロードできます。

詳しくは見ていませんが、後半のDemoで、IronPythonとの連携を見せているようです。

2005-11-02

[]$inputの謎(2)

パイプでオブジェクトが渡されたかどうか判断するには?

$inputのCloneメソッド、MoveNextメソッドを組み合わせることで、オブジェクトが渡されたかどうか判断できます。

パイプでオブジェクトが渡されたかどうか判断する
function existPipedObject
{
    $test = $input.clone()
    $test.MoveNext()
}

利用例
MSH C:\> ls | existPipedObject
True
MSH C:\> existPipedObject
False
MSH C:\>

「more」の改良

$inputの要素数が0個かどうかで分岐するようにしました。

function more
{
    $test = $input.Clone()
    if($test.MoveNext())
    {
        $input | out-host -paging
    }
    
    if($args[0] -ne $null)
    {
        get-content $args[0] | out-host -paging
    }
}

2005-11-01

[]$inputの謎(1)

「more」の挙動

「more」コマンドを作成する - PowerShell Memo

「パイプと引数を同時に渡すと、両方処理してしまう点が課題です」と書きましたが、Cygwin

ls | more test.txt

と打つと、パイプと引数の両方ともページング表示されました。

ということは、「more」コマンドを作成する - PowerShell Memoで書いたMSH「more」は、UNIXの「more」と同等処理ということになりますね。

「System.Array+SZArrayEnumerator」

System.Array+SZArrayEnumeratorはSystem.Arrayの内部クラスです。

System.ArrayのソースはDotNet247: #1 Guide To The Best Web Hosting Companiesで確認できます。

$inputがnullにならないのはなぜ?

パイプで渡されるのはObjectの配列です。

例えば、

get-process | more

を実行すると、存在するプロセスの数を要素数とするObjectがパイプに渡されます。

実際には「System.Diagnostics.Process」の配列ですね。


以下のようにパイプを利用していない場合は、

more xxx.txt

おそらく、要素数0個のObject配列が渡されているのだと思います。

そのため$inputはnullにならないのではないでしょうか。

Connection: close