Microsoftが無料提供しているWindows向けユーティリティー群「Windows Sysinternals」は、筆者のお気に入りのツールです。「Sysinternals Suite」は、Windows Sysinternalsのほとんど全てのユーティリティーを1つのZIPファイルにまとめて提供するものです。今回は、Sysinternals Suiteのインストールと更新をPowerShellスクリプトで自動化することに挑戦してみました。
「Windows Sysinternals」には多数のユーティリティーがありますが、頻繁に更新されるものがある一方、長い間、同じバージョンのままのものもあります。ユーティリティーの更新は、バグの修正や新機能の追加、新OSへの対応などのために不定期で行われます。
Windows Sysinternalsについては、筆者のお気に入りのツールでもありますし、このツールについて解説した書籍の翻訳を担当したこともあって、常に更新バージョンが出ていないかどうか、確認と更新バージョンへの入れ替えを欠かしません。
以前は更新版が出ると、Sysinternals Site DiscussionブログやWindows Sysinternalsの公式サイトでアナウンスされてきましたが、最近は更新版が出てもアナウンスされないケースが出てきました。
Windows Sysinternalsでは、URL「https://live.sysinternals.com/<ツールの実行ファイル名(例:procmon.exe)>」(現在は、https://にリダイレクトされるようになりました)の指定によるWebからの直接実行を可能にする「Sysinternals Live」が提供されています。
このSysinternals Liveの「files」ディレクトリをブラウザで直接参照することで、更新バージョンがあるかどうかを確認できることに気が付きました。
「files」ディレクトリには、各ツールのZIP形式のファイルが配置されています。このZIPファイルの日付を確認することで、最近更新されたツールを見つけることができます。また、1つでもツールが更新されると、ほとんど全てのツールをまとめたSysinternals SuiteのZIPファイル「SysinternalsSuite.zip」が再作成されるため、このZIPファイルの日付と同じ日付のツールが更新されていることが分かります(画面1)。
Sysinternals SuiteのZIPファイルを利用すると、Windows Sysinternalsのユーティリティーを一度にダウンロードして、ローカルの任意パスに展開して利用できます。展開先のパスをユーザーやシステムのPATH環境変数に登録しておけば、コマンドプロンプトやWindows PowerShell、「ファイル名を指定して実行」など、どこからでもファイル名だけでツールを呼び出すことができて便利です。
筆者は、Sysinternals Suiteを「C:\Program Files\SysinternalsSuite」ディレクトリに展開し、このパスをシステム環境変数のPATHに追加して利用しています。
しかし、ローカルに展開して利用するこの方法は、ユーティリティーの更新版が出たとき、入れ替え作業が意外と面倒です。個別のツールをダウンロードして同じディレクトリ内に上書きする、あるいはSysinternals Suiteの最新版をダウンロードして同じディレクトリに全て上書きするといった作業が必要です。
長年、今説明したような手作業を行ってきたのですが、PowerShellスクリプトで自動化して、作業を楽にしたいと考えるようになりました。そして完成したのが、以下の「InstallSysinternalsSuite.ps1」スクリプトです。
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $InstallTo = "$env:ProgramFiles\SysinternalsSuite" if (Test-Path "$env:TEMP\SysinternalsSuite.zip") { Remove-Item -Path "$env:TEMP\SysinternalsSuite.zip" } if (!(Test-Path "$InstallTo")) { Write-Host "SysinternalsSuite.zip をダウンロードしています ..." Invoke-WebRequest -uri "https://live.sysinternals.com/files/sysinternalssuite.zip" -outfile "$env:TEMP\sysinternalssuite.zip" -UseBasicParsing Write-Host "SysinternalsSuite.zip を $InstallTo に展開しています。..." Expand-Archive -Path "$env:TEMP\SysinternalsSuite.zip" -DestinationPath "$InstallTo" Write-Host "システム環境変数 PATH に $InstallTo を追加しています ..." $path = [Environment]::GetEnvironmentVariable("PATH", "Machine") $path += ";" + "$InstallTo" [Environment]::SetEnvironmentVariable("PATH", $path, "Machine") $env:PATH = $path Write-Host "SysinternalsSuite が $InstallTo にインストールされました。" } else { Write-Host "Sysinternals Suite は $InstallTo に既にインストールされています。`r`n" Write-Host "https://live.sysinternals.com/ で利用可能な最新版は ..." $webcontent = (Invoke-WebRequest -uri "https://live.sysinternals.com/files/" -UseBasicParsing).Content (((($webcontent.Replace("<br>","`r`n")).Replace("</A>","")).Replace("<A HREF=","")).Replace(">"," ")).split("`r`n")|Select-String "SysinternalsSuite.zip" Write-Host "`r`n" Write-Host "インストール済みの新しいユーティリティーの新しいバージョン TOP 5 を探しています ..." Get-ChildItem -Path "$InstallTo\*.exe"| Sort-Object LastWriteTime -Desc |Select-Object -first 5 | Ft LastWriteTime, Name [ValidateSet("y","n")] $res = Read-Host "Sysinternals Suite を最新版に入れ替えますか (y/n) ?" if ($res -eq "y") { Write-Host "SysinternalsSuite.zip をダウンロードしています ..." Invoke-WebRequest -uri "https://live.sysinternals.com/files/sysinternalssuite.zip" -outfile "$env:TEMP\sysinternalssuite.zip" -UseBasicParsing Write-Host "SysinternalsSuite.zip を $InstallTo に展開しています。..." Expand-Archive -Path "$env:TEMP\SysinternalsSuite.zip" -DestinationPath "$InstallTo" -Force Write-Host "Sysinternals Suite の最新バージョンに更新されました。" } }
このスクリプトと同等のものを、MicrosoftのTechNetスクリプトセンターが公開しています(メッセージが英語になっているなど、筆者が作成したスクリプトとは部分的に異なります)。
筆者のInstallSysinternalsSuite.ps1スクリプトは、「C:\Program Files\SysinternalsSuite」ディレクトリが存在しない場合、Sysinternals Liveから「SysinternalsSuite.zip」をダウンロードして展開し、システム環境変数PATHに「C:\Program Files\SysinternalsSuite」ディレクトリを追加します(画面2、画面3)。
また、インストール後、すぐに利用できるように、ユーザーの現在のPATH変数にも一時的にパスを追加しています(スクリプトの「$env:PATH = $path」の部分)。「C:\Program Files\SysinternalsSuite」ディレクトリはスクリプトが想定している既定のパスであり、$InstallTo変数の値を変更することで、別の場所に変更できるはずです(ただし、別のパスではテストしていません)。
最初の1行は、「Invoke-WebRequest」コマンドレットがTLS 1.2プロトコルを使用することを強制するものです。最初にこのスクリプトを作成したとき(2018年10月中ごろ)は、この行がなくても問題ありませんでした。
しかし、その後、Sysinternals LiveサイトがTLS 1.2プロトコルの使用を強制するようになり、Windows 10 バージョン1803以前の既定の環境では、Invoke-WebRequestコマンドレットが「invoke-webrequest:接続が切断されました:送信時に、予期しないエラーが発生しました」というエラーで失敗するようになりました。
Windows 10 バージョン1803以前は、既定でSSL 3.0(Ssl3)またはTLS 1.0(Tls)プロトコルを使用しますが、この1行を追加することでTLS 1.2(Tls12)プロトコルを強制的に使用させることができます。
Sysinternals Suiteが既定のパスにインストール済みの環境でInstallSysinternalsSuite.ps1スクリプトを実行した場合、Sysinternals Liveの「files」ディレクトリからSysinternalsSuite.zipの作成日時を取得し、表示するようにしてあります。筆者が作成したスクリプトでは少々強引なやり方でSysinternalsSuite.zipの日時を表示させています。Sysinternals Liveのサイトのページの構成が変わると、期待通りに動かなくなる可能性があることはご了承ください。
また、ローカルの既定のパスに存在する実行可能ファイル(*.exe)を検索し、最終更新日時が新しいものから上位5ファイルを表示するようにしています。この機能は公開スクリプトには含まれない、後で追加した機能です。ただし、実行可能ファイルの最終更新日時は、それが含まれるZIPファイルの最新更新日時と一致しないことに注意してください(数日前など)。
この2つの情報に基づいて、ローカルのSysinternals SuiteをSysinternals Liveで利用可能な最新版に総入れ替えするかどうかを「y」または「n」で指示できるようにしました(画面4)。
あまり美しくなく、半ば強引なコードを含むスクリプトですが、少なくとも筆者の環境では期待通りに動作しますし、入れ替え作業が劇的に楽になりました。もしよかったら使ってみてください。ただし、「C:\Program Files\SysinternalsSuite」ディレクトリ以外のパスに既にSysinternals Suiteが展開済みであり、PATH環境変数に追加している環境では、全体にこのスクリプトをそのまま実行しないでください。少し改造すれば、システム全体ではなく、管理者権限なしでユーザー別の環境に展開することもできるでしょう。
岩手県花巻市在住。Microsoft MVP:Cloud and Datacenter Management(Oct 2008 - Sep 2016)。SIer、IT出版社、中堅企業のシステム管理者を経て、フリーのテクニカルライターに。Microsoft製品、テクノロジーを中心に、IT雑誌、Webサイトへの記事の寄稿、ドキュメント作成、事例取材などを手掛ける。個人ブログは『山市良のえぬなんとかわーるど』。近著は『Windows Server 2016テクノロジ入門−完全版』(日経BP社)。
Copyright © ITmedia, Inc. All Rights Reserved.