#概要
下記のような構造を持つ常駐型のPowerShellプログラム(例えばこちらのスクリプトなど)が、(最小化しても)常にタスクバー上に表示されていると目障りなのでタスクトレイ(正式には"通知領域")に入れます。
while ($True) {
... #何かの処理
...
Start-Sleep <n>
}
#実装
以下のソースを対象のスクリプト(拡張子 .ps1)の先頭部分に追加(埋め込み)し、実行(右クリックして「PowerShellで実行」)することでタスクトレイの中に入れることができます。最後のコメント行は削除しないでください(2桁目の"!"が重要)。
なお、対象スクリプトには引数がなく、したがってparam文を持たないものとします(常駐型なら少しの工夫によりそのような形式で書ける筈)。
※こちらの記事を参考にしました。
#@Powershell -NoP -W Hidden -C "$PSCP='%~f0';$PSSR='%~dp0'.TrimEnd('\');&([ScriptBlock]::Create((gc '%~f0'|?{$_.ReadCount -gt 1}|Out-String)))" %* & exit/b
# by earthdiver1 V1.05
if ($PSCommandPath) {
$PSCP = $PSCommandPath
$PSSR = $PSScriptRoot
$code = '[DllImport("user32.dll")]public static extern bool ShowWindowAsync(IntPtr hWnd,int nCmdShow);'
$type = Add-Type -MemberDefinition $code -Name Win32ShowWindowAsync -PassThru
[void]$type::ShowWindowAsync((Get-Process -PID $PID).MainWindowHandle,0) }
Add-Type -AssemblyName System.Windows.Forms, System.Drawing
$menuItem = New-Object System.Windows.Forms.MenuItem "Exit"
$menuItem.add_Click({$notifyIcon.Visible=$False;while(-not $status.IsCompleted){Start-Sleep 1};$appContext.ExitThread()})
$contextMenu = New-Object System.Windows.Forms.ContextMenu
$contextMenu.MenuItems.AddRange($menuItem)
$notifyIcon = New-Object System.Windows.Forms.NotifyIcon
$notifyIcon.ContextMenu = $contextMenu
$notifyIcon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($PSCP)
$notifyIcon.Text = (Get-ChildItem $PSCP).BaseName
$notifyIcon.Visible = $True
$_syncHash = [hashtable]::Synchronized(@{})
$_syncHash.NI = $notifyIcon
$_syncHash.PSCP = $PSCP
$_syncHash.PSSR = $PSSR
$runspace = [RunspaceFactory]::CreateRunspace()
$runspace.ApartmentState = "STA"
$runspace.ThreadOptions = "ReuseThread"
$runspace.Open()
$runspace.SessionStateProxy.SetVariable("_syncHash",$_syncHash)
$scriptBlock = Get-Content $PSCP | ?{ $on -or $_[1] -eq "!" }| %{ $on=1; $_ } | Out-String
$action=[ScriptBlock]::Create(@'
# param($Param1, $Param2)
Start-Transcript -LiteralPath ($_syncHash.PSCP -Replace '\..*?$',".log") -Append
Function Start-Sleep { [CmdletBinding(DefaultParameterSetName="S")]
param([parameter(Position=0,ParameterSetName="M")][Int]$Milliseconds,
[parameter(Position=0,ParameterSetName="S")][Int]$Seconds,[Switch]$NoExit)
if ($PsCmdlet.ParameterSetName -eq "S") {
$int = 5
for ($i = 0; $i -lt $Seconds; $i += $int) {
if (-not($NoExit -or $_syncHash.NI.Visible)) { exit }
Microsoft.PowerShell.Utility\Start-Sleep -Seconds $int }
} else {
$int = 100
for ($i = 0; $i -lt $Milliseconds; $i += $int) {
if (-not($NoExit -or $_syncHash.NI.Visible)) { exit }
Microsoft.PowerShell.Utility\Start-Sleep -Milliseconds $int }}}
$script:PSCommandPath = $_syncHash.PSCP
$script:PSScriptRoot = $_syncHash.PSSR
'@ + $scriptBlock)
$PS = [PowerShell]::Create().AddScript($action) #.AddArgument($Param1).AddArgument($Param2)
$PS.Runspace = $runspace
$status = $PS.BeginInvoke()
$appContext = New-Object System.Windows.Forms.ApplicationContext
[void][System.Windows.Forms.Application]::Run($appContext)
exit
#! ---------- ScriptBlock (Line No. 28) begins here ---------- DO NOT REMOVE THIS LINE
- バッチファイルとして実行(スタートアップに登録しやすい。ダブルクリックも可能)したい場合は、先頭行のコメントをはずして以下のコマンドを有効にします。
@Powershell -NoP -W Hidden -C "$PSCP='%~f0';$PSSR='%~dp0'.TrimEnd('\');&([ScriptBlock]::Create((gc '%~f0'|?{$_.ReadCount -gt 1}|Out-String)))" %* & exit/b
- 起動した後、プログラムを終了する必要が生じた場合には、タスクトレイ上のアイコンを右クリックして Exit を選択します。待機状態時に終了させるために Start-Sleep コマンドレットをカスタマイズしています。既定では待機時間が秒単位の場合は5秒毎、ミリ秒単位の場合は100ミリ秒毎に終了判定を行いますが、必要に応じて36,41行目の $int 変数の値を調整してください。
途中終了させたくないStart-Sleepコマンドレットがある場合は、当該 Start-Sleep に -NoExit パラメータを追加してください。 - 一瞬、黒いコンソール画面が表示されてしまうのがどうしても気になる方は、ショートカットを作成してプロパティの「実行時の大きさ」を「最小化」としてください。
(2018.5.1修正) $PSScriptRoot を script スコープで参照可能としました。
クリエイティブ・コモンズ 表示 - 継承 4.0 国際