LoginSignup
11
20

More than 5 years have passed since last update.

常駐型PowerShellプログラムをタスクトレイに入れる

Last updated at Posted at 2017-12-03

概要

下記のような構造を持つ常駐型の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 国際

11
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
20