Powershellをランチャーにする

長らく、コマンドプロンプトをランチャーとして使ってきたのですが、XPの寿命も尽きようとしているので、Powershellに引っ越すことにしました。
いろいろ便利ですから!


CUIランチャーとして使うためにやったことのメモです。



今までのCUIランチャー

コマンドプロンプトをconsoleというタイトルで起動。
kterm」と入力すると別ウインドウを立ち上げる。
よく使うプログラムにはaliasをつけておく。
kterm」の「logout」はウインドウを閉じるだけ。
「console」の「logout」はPCをシャットダウンする。


こんな感じです。
aliasはPowershellの機能にありますから、kterm/logoutの工夫ですね。
ついでに「ls」の表示を好みにしました。
色つき嬉しい!(ハードコードだから変更はスクリプト修正)
「ls -l」「ls -la」あたりも通るように。
あとは、「rm」では確認を、「rm -f」で無条件削除に変更。
確認は-Confirmだとデフォルト「はい」を避けたいので、車輪の再発明
「-r」オプションもなんとなく実装。

Powershell起動時の設定と言えば?

$profileですね。
Set-ExecutionPolicy は RemoteSigned あたりで。
notepad $profile でこれだけ書きました。

# modules
# $env:USERPROFILE\Documents\WindowsPowerShell\Modules
Import-Module -name login
Import-Module -name logout

# settings
Remove-Item -Path alias:ls
Remove-Item -Path alias:rm

$profileに何もかも書いてもよかったのですが、ま、可読性等です。
Module内でAllScopeのAliasを消す方法が不明です、、、。

loginモジュール

2014/01/27 いろいろくっつけて、あと管理者権限の表示に対応した。

function Start-Host() {
	Param(
		[string]$Title = "kterm",
		[switch]$Edit
	)

	if($Edit) {
		iex "$EDITOR $env:USERPROFILE\Documents\WindowsPowerShell\Modules\login\login.psm1"
	} else {
		if((New-Object System.Security.Principal.WindowsPrincipal([System.Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)) {
			$Title += " : admin"
		}
		(Get-Host).UI.RawUI.WindowTitle = $Title

		if($Title -match '^console(?: .*)?$') {
			#start mail
		}

	}
}

function Get-Types() {
	Param(
		[string]$Match,
		[string]$Name,
		[switch]$Private
	)

	$res = @()
	if($Name.length -gt 0 -and $Name -as [Type]) {
		$res += ($Name -as [type])
	}
	if($res.length -eq 0) {
		if($Match.length -le 0 -and $Name.length -gt 0) {
			$res = $Name -split '\.'
			$Match = '^' + $res[$res.length - 1] + '$'
			$res = @()
		}
		foreach($ass in [AppDomain]::CurrentDomain.GetAssemblies()) {
			foreach($t in $ass.GetTypes()) {
				if(($t.IsPublic -or $Private) -and ($t.Name -match $Match)) {
					$res += $t
				}
			}
		}
	}

	return $res
}

function Get-TypeMember() {
	Param(
		$Target,
		[switch]$Static,
		[switch]$Private
	)

	if($Target -is [String]) {
		if($Target -match '^\[[^\]]+]$') {
			$Target = (($Target -replace '^\[([^\]]+)]$', '$1') -as [type])
		} else {
			$ts = (Get-Types $Target)
			if($ts -ne $null -and -not $ts.length) {
				$Target = $ts
			} elseif(!$ts.length) {
				Write-Error ($Target + ' is not found!')
				$Target = $null
			} else {
				$ts | %{ Write-Host ('[' + $_.FullName + ']') }
				return Get-TypeMember (Read-Host ?)
			}
		}
	}

	$res = @()
	if($Target -is [Type]) {

		function getMembersSub($tar, [string]$para, [string]$pre) {
			function getTypeName($type) {
				$res = $type.ToString()
				$res = $res -replace 'System.Boolean', 'bool'
				$res = $res -replace 'System.String', 'string'
				$res = $res -replace 'System.Int32', 'int'
				$res = $res -replace 'System.Char', 'char'
				return $res
			}

			$res = @()
			foreach($mi in $tar.GetMembers($para)) {
				$def = ''
				if(-not $mi.IsPublic -and ($mi.MemberType -ne 'Property' -and $mi.MemberType -ne 'NestedType')) { $def = '# ' }
				$def += $pre
				$type = $mi.MemberType.ToString()
				switch($type) {
					Method {
						$def += (getTypeName $mi.ReturnType) + ' ' + $mi.Name + '('
						$comma = $false
						foreach($pi in $mi.GetParameters()) {
							if($comma) { $def += ', ' }
							$def += (getTypeName $pi.ParameterType) + ' ' + $pi.Name
							$comma = $true
						}
						$def += ')'
					}
					Constructor {
						$type = 'CodeMethod'
						$def += $tar.Name + '('
						$comma = $false
						foreach($pi in $mi.GetParameters()) {
							if($comma) { $def += ', ' } else { $comma = $true }
							$def += (getTypeName $pi.ParameterType) + ' ' + $pi.Name
						}
						$def += ')'
					}
					Property {
						$def += (getTypeName $mi.PropertyType) + ' ' + $mi.Name
						$comma = $true
						foreach($pi in $mi.GetIndexParameters()) {
							if($comma) { $def += '('; $type = 'ParameterizedProperty'; $comma = $false } else { $def += ', ' }
							$def += (getTypeName $pi.ParameterType) + ' ' + $pi.Name
						}
						if(-not $comma) { $def += ')' }
						$def += ' {'
						if($mi.CanRead) { $def += 'get;' }
						if($mi.CanWrite) { $def += 'set;' }
						$def += '}'
					}
					Field {
						$type = 'Properties'
						$def += (getTypeName $mi.FieldType) + ' ' + $mi.Name
					}
					NestedType {
						$type = 'PropertySet'
						$def += $tar.FullName + '+' + $mi.Name
					}
				}
				$res += (New-Object Microsoft.Powershell.Commands.MemberDefinition($Target.FullName, $mi.Name, $type, $def))
				#if($type -eq 'PropertySet') { $res += (getMembersSub $mi $para $pre) }
			}
			return $res
		}

		$def = ''
		if($Static) {
			$def = 'static '
			$ts = 'Static, Public'
		} else {
			$ts = 'Instance, Public'
		}
		if($Private) { $ts += ', NonPublic' }
		$res = getMembersSub $Target $ts $def
	} elseif($Target -ne $null) {
		$res = (Get-Member -InputObject $Target)
	}

	return $res
}

function kterm {
	if ($args -eq $null -or $args.length -eq 0) {
		start powershell
	} else {
		start powershell -ArgumentList $args
	}
}
function ls {
	Param(
		[switch]$l,
		[switch]$a,
		[switch]$t,
		[switch]$la,
		[switch]$lt
	)

	$cmd = "Get-Childitem "
	if ($la) {
		$l = $true
		$a = $true
	}
	if ($lt) {
		$l = $true
		$t = $true
	}
	if ($args -ne $null -and $args.Length -gt 0) {
		$cmd += $args + " "
	}
	if ($a) {
		$cmd += "-Force "
	}
	if ($t) {
		$cmd += "| Sort-Object -Property LastWriteTime -Descending "
	}
	if($l) {
		Invoke-Expression $cmd
	} else {
		$cs = Invoke-Expression $cmd
		if($cs -ne [System.Object[]]) { $cs = @($cs) }
		$len = ($cs | ForEach-Object {if($_ -ne $null -and $_.Name -ne $null) {if($res -lt [Text.Encoding]::Default.GetByteCount($_.Name)){$res=[Text.Encoding]::Default.GetByteCount($_.Name)}}} -Begin {$res=0} -End {$res})
		$max = (Get-Host).UI.RawUI.WindowSize.Width
		if($len -ge $max) { $len = $max - 1 }
		$max = [math]::Truncate($max / ($len + 1))
		$j = 1
		for($i = 0; $i -lt $cs.Length; $i++) {
			$color = "Gray"
			if($cs[$i] -is [System.IO.DirectoryInfo]) { $color = "Cyan" }
			if($cs[$i].Extension -match "^.(ps1|lnk|exe)$") { $color = "Green" }
			if($cs[$i].Extension -match "^.(zip|cab|lzh)$") { $color = "Yellow" }
			$name = $cs[$i].Name
			if($j -eq $max) {
				Write-Host -ForegroundColor $color $name.PadRight($len - [Text.Encoding]::Default.GetByteCount($name) + $name.Length)
				$j = 1
			} elseif($name -ne $null) {
				Write-Host -NoNewLine -ForegroundColor $color $name.PadRight($len - [Text.Encoding]::Default.GetByteCount($name) + $name.Length + 1)
				$j++
			}
		}
		if($j -ne 1) { Write-Host }
	}
}
function rm {
	Param(
		[switch]$r,
		[switch]$rf,
		[switch]$f
	)

	if($rf) {
		$r = $true
		$f = $true
	}
	if(!$f) {
		$f = ((Read-Host "$args 削除しますか?(y/N)") -eq 'y')
	}
	if($f) {
		if($r) {
			Remove-Item -Recurse $args
		} else {
			Remove-Item $args
		}
	}
}
function which {
	for($i = 0; $i -lt $args.length; $i++) {
		Get-Command $args[$i] | %{ $_.Definition }
	}
}


# settings
$Env:XYZZYHOME = "D:\tools\editor\xyzzy"
$Env:TZ = "JST-9"

$rawui = (Get-Host).UI.RawUI
$rawuisize = $rawui.BufferSize
$rawuisize.Height = 3000
$rawui.BufferSize = $rawuisize

$global:EDITOR = "xyzzy"

$tooldir = "d:\tools"


# alias
set-alias -name login -value Start-Host
set-alias -name grep -value Select-String
set-alias -name gt -value Get-Types

set-alias -name xyzzy -value $Env:XYZZYHOME\xyzzycli.exe
set-alias -name winmerge -value $tooldir\editor\WinMerge\winmerge
set-alias -name uwsc -value $tooldir\utility\uwsc\uwsc


Start-Host


Export-ModuleMember -Function * -Alias *

環境設定を押し込んでます。
最初のプロセスだけは、「Start-Host("console")」を行う想定です。

logoutモジュール

function Exit-Host() {
	Param([switch]$Edit)

	if($Edit) {
		iex "$EDITOR $env:USERPROFILE\Documents\WindowsPowerShell\Modules\logout\logout.psm1"
	} else {


		# proc
		#read-host "Push Enter key! "


		if((Get-Host).UI.RawUI.WindowTitle -match '^console(?: .*)?$') {
			Write-Host "Shutdown process starting."
			Read-Host "Push Enter key. "
			shutdown /s /t 3
		} else {
			exit
		}
	}
}


# alias
set-alias -name logout -value Exit-Host


Export-ModuleMember -Function * -Alias *

「console」のウインドウで「logout」すると、シャットダウンする算段です。

スタートアップ

Start-Host("console")は、スタートアップに登録するショートカットで行います。
ショートカットの内容は「C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoExit -Command "login 'console'"」です。