PoweShell에서 Windows의 작업 트레이에 고양이를 달려 보았습니다 🐈

18833 단어 PowerShell
Windows의 작업 표시줄에서도 고양이를 달려 보았습니다 🐈 이라는 기사를 읽었습니다. 필자 쪽은 「어쩔 수 없는 어플」이라고 겸손하고 있습니다만, 귀여운 고양이가 태스크 트레이에 상주해 주면, 개발로 살벌한 마음은 극적으로 치유되어 갈 것입니다. CPU 부하에 따라 달리는 속도가 달라진다는 것도 단순한 농담 앱으로 끝나지 않는 훌륭한 아이디어입니다.

그러나 나는 생각했다.

"CPU 부하에 맞춰 달리는 속도가 바뀌는 고양이를 태스크 트레이에 표시할 정도라면 PowerShell에서도 쓸 수 있을까?"

PowerShell은 Windows에 내장된 강력한 스크립팅 언어입니다. Windows에 할 수 있는 일은 대체로 기술할 수 있고, 신형 코로나 바이러스의 세계 감염 상황을 파악 그렇다고 할 수 있는 PowerShell 라면, 당연히 고양이를 달릴 수가 있을 것입니다.

결과



할 수 있었습니다.



먼저 이동하려면 여기 에서 다운로드한 Zip 파일의 압축을 풀고 init.vbs 를 실행하십시오.

2020/08/21 추가



인터넷에서 얻은 PowerShell 파일은 보안상의 이유로 실행할 수 없으므로 처음 실행할 때 unblock.bat를 실행하여 차단을 해제하십시오. ㅎㅎㅎ 씨, 지적 해 주셔서 감사합니다!

소스 코드



짧기 때문에 전문을 붙여 버립니다.

runcat.ps1
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

# ウィンドウを非表示化
$cscode = @"
    // Win32Api を読み込むための C# コード
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    // ウィンドウの状態を制御するため ShowWindowAsync() を extern する
    public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
"@
$Win32Functions = Add-Type -MemberDefinition $cscode -name Win32ShowWindowAsync -namespace Win32Functions -PassThru
$Win32Functions::ShowWindowAsync((Get-Process -PID $pid).MainWindowHandle, 0) > $null # bool 値を返すので null に捨てる

# タスクトレイにアイコンを作成する
$notifyIcon = New-Object System.Windows.Forms.NotifyIcon
$notifyIcon.Visible = $true

# ダークモード判定
$theme = "light"
if ((Get-ItemProperty -Path "Registry::HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize").AppsUseLightTheme -eq 0) {
    $theme = "dark"
}

# リソースの読みこみ
$path = Split-Path -Parent $MyInvocation.MyCommand.Path
$cats = @(
    New-Object System.Drawing.Icon -ArgumentList "$path\\resources\\${theme}_cat0.ico";
    New-Object System.Drawing.Icon -ArgumentList "$path\\resources\\${theme}_cat1.ico";
    New-Object System.Drawing.Icon -ArgumentList "$path\\resources\\${theme}_cat2.ico";
    New-Object System.Drawing.Icon -ArgumentList "$path\\resources\\${theme}_cat3.ico";
    New-Object System.Drawing.Icon -ArgumentList "$path\\resources\\${theme}_cat4.ico"
)

# CPU 負荷の取得が GUI プロセスをブロックしないよう、バックグラウンドジョブとして実行する
$job = Start-Job -ScriptBlock {
    Get-Counter -Counter "\Processor(_Total)\% Processor Time" -Continuous | ForEach-Object {
        $_.CounterSamples.CookedValue
    }
}

# CPU使用率を定期的に取得するため、タイマーオブジェクトを作成する
$cpuTimer = New-Object Windows.Forms.Timer

# タイマーのイベントハンドラからも書き込みたい変数を script スコープで宣言
$script:cpuUsage = 1

$cpuTimer.Add_Tick( {
        $cpuTimer.Stop()

        # バックグラウンドジョブから結果を取得する
        $script:cpuUsage = [double](Receive-Job $job)[0]

        $cpuTimer.Start()
    })

$cpuTimer.Interval = 3 * 1000
$cpuTimer.Start()

# タスクトレイアイコンを任意のタイミングで差し替えるため、タイマーオブジェクトを作成する
$animateTimer = New-Object Windows.Forms.Timer

# タイマーのイベントハンドラからも書き込みたい変数を script スコープで宣言
$script:idx = 0

$animateTimer.Add_Tick( {
        $animateTimer.Stop()

        # 次のコマを表示
        $notifyIcon.Icon = $cats[$script:idx++]
        if ($script:idx -eq 5) { $script:idx = 0 }

        # CPU 使用率をバックグラウンド処理結果から取得
        $notifyIcon.Text = $script:cpuUsage
        # ネコチャンの速さを変更
        $animateTimer.Interval = (200.0 / [System.Math]::Max(1.0, [System.Math]::Min(20.0, $script:cpuUsage / 5)))

        $animateTimer.Start()
    })

$animateTimer.Interval = 200
$animateTimer.Start()

# メッセージループで利用する ApplicationContext を作成する
$applicationContext = New-Object System.Windows.Forms.ApplicationContext

# アイコンクリック時のイベントハンドラ
$notifyIcon.add_Click( {
        # メッセージループを終了
        $applicationContext.ExitThread()
    })

# アイコンを押すまで終わらないよう、メッセージループを回す
[System.Windows.Forms.Application]::Run( $applicationContext )

# 終了処理
$cpuTimer.Stop()
$animateTimer.Stop()
$notifyIcon.Visible = $false


Win32API를로드하려면 C# 스 니펫을 사용하고 있지만 PowerShell을 거의 쓸 수 없습니까? PowerShell에서 타스트레이 아이콘을 만지는 방법과 DOS 창을 표시하지 않는 시작에 대한 자세한 내용은 여기 문서를 참조하십시오. 감사합니다.

작은 자료로서, 퍼포먼스 정보를 취득하는 Get-Counter 의 응답이 늦었기 때문에, 렌더링을 블록 하지 않게 백그라운드 작업으로 처리시키고 있습니다. Get-Counter 에는 계속해서 정보를 계속 얻는다 -Continuous 옵션이 있기 때문에, 작업은 1개만 시작하고 있습니다. 개발중 이 옵션을 눈치채지 못하고 일정 간격으로 작업을 계속 늘려 메모리 소비가 터무니 없게 되어 버렸습니다. PowerShell의 작업은 별도의 프로세스로 시작되므로 비용이 바보가 될 수없는 것 같습니다.

코드 중에 오류가 표시되지만 PowerShell ISE 및 VS Code의 공식 확장 기능에서는 화가 나지 않으므로 Qiita/Rouge 측의 문제라고 생각됩니다.

고양이와 함께 즐거운 PowerShell 라이프를.

참고 링크


  • 나는 PowerShell이지만 너의 작업 트레이에서 살고 싶다.
  • Win32 응용 프로그램에서 Windows 10의 라이트 / 다크 모드를 감지하는 방법
  • PowerShell로 서버에서 실행되는 프로세스를 알고 싶습니다.
  • get-counter as job -continuous
  • PowerShell에서 차단된 파일의 영역 제거
  • 좋은 웹페이지 즐겨찾기