Windows
ImageMagick
PowerShell

PowerShellで好きな画像をフォルダアイコンに設定しよう

Windowsにはフォルダアイコンを好きなアイコンに変更する機能がありますが、この機能を使っている方はかなり少ないのではないでしょうか。そもそもアイコンを変える必要性を感じないと言われれば、まあその通りなんですが、少し気分転換して日々のエクスプローラーでの作業が少しでも楽しくなればいいかなと思います。

フォルダを独自アイコンに変更するのは面倒

フォルダアイコンを変更するには、

  1. 適当なアイコンを探してくる ← 適当なアイコン探すのが面倒。アイコンは画像より圧倒的に少ない。
  2. 適当なアイコンがない場合は自分で作る。
    1. 適当な画像を探す
    2. 画像を正方形に変形する
    3. 画像をアイコンに変更する ← 画像をアイコンに変換するツールを探さないといけない。
  3. エクスプローラー上でフォルダのプロパティ画面を出してアイコンの変更を行う。

という手順が必要です。これをフォルダ一つ一つにやっていたら面倒くさくてもういいやとなります。

そこでPowerShellで自動化しようと思いました。当初はPowerShellとWindowsに最初から入っているツールのみで実現しようと思ったのですが、ふと試したImageMagickが強力すぎたのでImageMagickを使いました。

画像からアイコンを作成してフォルダに適用する関数

確認した環境は以下の通りです。

  • Windows10 64 Pro
  • PSVersion 5.1
  • ImageMagick 7.0.5-7 Q16 x64

作成した関数は以下です。

function Set-FolderIcon
{
    param
    (
        # 対象フォルダのパス
        [Parameter(Mandatory=$true, Position=0)]
        $Path,
        # 画像ファイルのパス
        [Parameter(Mandatory=$true, Position=1)]
        $Image,
        # 短い辺に合わせてクロップする(デフォルトは塗り足し)
        [switch]
        $Crop,
        # 角を丸くする
        [switch]
        $Round
    )

    $ErrorActionPreference = "Stop"

    # 対象フォルダと画像のFileInfo取得
    $targetDir = Get-Item -LiteralPath $Path
    $srcImage = Get-Item -LiteralPath $Image

    # カレントディレクトリを対象フォルダへ変更
    Push-Location -LiteralPath $targetDir

    ### アイコン作成

    # 既存のファイル名と重複しないアイコン名を取得
    $iconName = &{ $i=2; $n="folder.ico"; while(Test-Path $n){ $n="folder{0}.ico" -f $i++ } $n }
    # 切り抜くサイズを決める (デフォは画像の長辺を、クロップなら短辺を採用する)
    $l = &{ $func = if($Crop) {"min"} else {"max"}; magick identify -format "%[fx:${func}(w,h)]" $srcImage.FullName }
    # 角丸の半径
    $r = if($Round) { $l/6 } else { 0 }
    # アイコン生成
    magick -size "${l}x${l}" xc:none -draw "roundrectangle 0,0 $($l-1),$($l-1) $r,$r" `
        $srcImage.FullName -gravity center -background none -extent "${l}x${l}" -compose src-in -composite `
        -filter Lanczos -depth 32 -define icon:auto-resize=256,128,96,72,64,48,32,24,16 $iconName

    # 生成したアイコンのFileInfo取得
    $icon = Get-Item $iconName

    ### iniファイルに登録

    # Windows APIを使う
    $code = @'
    [DllImport("KERNEL32.DLL")]
    public static extern int WritePrivateProfileString(string lpAppName, string lpKeyName, string lpString, string lpFileName);
'@
    Add-Type -MemberDefinition $code -Namespace WinApi -Name Kernel -Language CSharp

    # iniファイル取得(無い時は作成)
    $iniFile = if(Test-Path desktop.ini){ Get-Item desktop.ini -Force } else { New-Item desktop.ini }
    # iniファイル書き換え
    [WinApi.Kernel]::WritePrivateProfileString(".ShellClassInfo", "IconResource", $iconName, $iniFile) > $null
    # 属性変更
    $iniFile.Attributes = "System", "Hidden"
    $icon.Attributes = "System", "Hidden"
    $targetDir.Attributes = "ReadOnly"

    Pop-Location
    $icon
}

作成したアイコンは対象フォルダ直下に置かれ隠しファイルとなります。

使ってみる

img_20180505070529.png

C:\sample\フォルダ1フォルダのアイコンを画像C:\sample\a.pngに変更する

Set-FolderIcon "C:\sample\フォルダ1" "C:\sample\a.png"

img_20180505070644.png

ちゃんと変更されました。

一括でフォルダアイコンを変更

ちまちまやると面倒なのでせっかくなので一気にやりたいです。まず対象フォルダにアイコンにしたい画像を配置します。今回は画像の名前をindex.jpgに統一します。

img_20180505073357.png

フォルダの中はこんな感じです。

img_20180505073938.png

C:\sample2内のフォルダを一括してアイコン適用してみます。

PS C:\sample2> Get-ChildItem -Directory | foreach { Set-FolderIcon $_ (Join-Path $_ index.jpg) -Crop -Round }

img_20180505075526.png

一括で適用できました。-Cropをつけることで画像の短辺を基準に画像が正方形に切り抜かれ、-Roundをつけると角を丸められます。

注意点

OSのアイコンキャッシュが残っているとすぐには反映されない場合があるのでその場合はアイコン名を変えてdesktop.ini内のアイコン名も変更してやるとすぐに反映されます。アイコンキャッシュはいつの間に更新されるようですが、そのタイミングが分からないので。

ImageMagickのアイコン作成コマンドについて

今回ImageMagick使ってみてすごく強力だけど複雑すぎて体系的に学ぶのは大変だなと思いました。今回使ったコマンドについてざっくりメモしておきます。

magick -size 256x256 xc:none -draw "roundrectangle 0,0 255,255 40,40" `
        src.png -gravity center -background none -extent 256x256 -compose src-in -composite `
        -filter Lanczos -depth 32 -define icon:auto-resize=256,128,96,72,64,48,32,24,16 dest.ico
  1. -size 256x256 ・・・ 256x256のキャンパスを作る。
  2. xc:none ・・・ 単色透明のレイヤーを開く。
  3. -draw "roundrectangle 0,0 255,255 40,40"・・・ 角丸の矩形を描画する。
  4. src.png・・・ 新たなレイヤーにsrc.pngを開く。
  5. -gravity center・・・ キャンパスの中心に配置する。
  6. -background note ・・・ デフォルトの背景を透明とする(塗り足しされる色)。
  7. -extent 256x256 ・・・ キャンパスサイズを256x256に変更する。-gravityの指定が基準になる。
  8. -compose src-in・・・ レイヤーの重ねあわせの効果を指定。src-inは下のレイヤの不透明の部分が置 き換えられる。つまり上の画像が切り抜きされる。
  9. -composite ・・・ 実際に結合する 。
  10. -filter Lanczos ・・・ 拡大縮小のアルゴリズムを指定。
  11. -depth 32 ・・・ 深度を指定。
  12. -define icon:auto-resize=256,128,96,72,64,48,32,24,16 ・・・ 自動で指定サイズのマルチアイコンを作成する。
  13. dest.ico ・・・ ファイルに保存する

ImageMgickが思ってた以上にいろんなことができて改めてすごいなと思いました。本当はPowerShellネタとしたかったのですが、ImageMgickの比重が大きくタイトル詐欺になってすみません。
以上ここまで見ていただいてありがとうございました。