Skip to content

Instantly share code, notes, and snippets.

@uemuraj
Last active November 29, 2024 07:54
Show Gist options
  • Save uemuraj/4ef91ec039da85c0db88a493578a301d to your computer and use it in GitHub Desktop.
Save uemuraj/4ef91ec039da85c0db88a493578a301d to your computer and use it in GitHub Desktop.
エクスプローラーの「PC」に表示されるアイコンを選択します
<#
.SYNOPSIS
エクスプローラーの「PC」に表示されるアイコンを選択します
.DESCRIPTION
以下のキーを使って操作します。
[ENTER] ... 選択結果をレジストリへ書き込んで終了します。選択は、サインアウト後に有効になります。
[SPACE] ... 各項目を On/Off できます。
[UP][DOWN] ... 項目間を移動できます。
[ESC] ... 何もせず終了します。
#>
using namespace System.Management.Automation.Host
function SetBufferContent([Coordinates] $pos, [char] $char) {
$cell = $Host.UI.RawUI.NewBufferCellArray($char, $Host.UI.RawUI.ForegroundColor, $Host.UI.RawUI.BackgroundColor)
$Host.UI.RawUI.SetBufferContents($pos, $cell)
}
class CheckBox {
[bool] $checked
[Coordinates] $pos
CheckBox([int] $x, [int] $y, [bool] $checked) {
$this.pos = [Coordinates]::new($x, $y)
$this.checked = $checked
$this.Mark()
}
[void] Flip() {
$this.checked = -not $this.checked
$this.Mark()
}
[void] hidden Mark() {
if ($this.checked) {
SetBufferContent $this.pos '*'
}
else {
SetBufferContent $this.pos ' '
}
}
}
function MultiSelection([ScriptBlock] $Initial, [ScriptBlock] $Selected, [ScriptBlock] $Unselected) {
<#
.SYNOPSIS
テキストベースの複数選択メニューを表示します
.PARAMETER Initial
アイテムの初期状態を返すスクリプトブロック。 True を返すと、メニューには選択済として表示されます。
.PARAMETER Selected
終了時、アイテムが選択済だった場合に呼び出されるスクリプトブロック。 [ESC] で終了した場合は呼び出されません。
.PARAMETER Unselected
終了時、アイテムが非選択だった場合に呼び出されるスクリプトブロック。 [ESC] で終了した場合は呼び出されません。
#>
$objects = @($input)
$objects | ForEach-Object { Write-Host -NoNewline " [ ] "; Write-Host $_ }
$pos = $Host.UI.RawUI.CursorPosition
$count = $objects.Count
$items = $objects | ForEach-Object { [CheckBox]::new($pos.X + 2, $pos.Y - $count--, (& $Initial)) }
$index = 0
$Host.UI.RawUI.CursorPosition = $items[$index].pos
try {
while ($true) {
$key = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
if ([System.ConsoleKey]::Enter -eq $key.VirtualKeyCode) {
break
}
if ([System.ConsoleKey]::Escape -eq $key.VirtualKeyCode) {
return
}
if ([System.ConsoleKey]::Spacebar -eq $key.VirtualKeyCode) {
$items[$index].Flip()
continue
}
if ([System.ConsoleKey]::DownArrow -eq $key.VirtualKeyCode) {
$index++
if ($index -eq $items.Count) {
$index = 0
}
$Host.UI.RawUI.CursorPosition = $items[$index].pos
continue
}
if ([System.ConsoleKey]::UpArrow -eq $key.VirtualKeyCode) {
$index--
if ($index -lt 0) {
$index = 0
}
$Host.UI.RawUI.CursorPosition = $items[$index].pos
continue
}
}
}
finally {
$Host.UI.RawUI.CursorPosition = $pos
}
$index = 0
$objects | ForEach-Object { if ($items[$index++].checked) { & $Selected } else { & $Unselected } }
}
enum Policy {
Show = $true
Hide = $false
}
class FolderDescription {
[bool] static $dirty
[string] $path
[string] $desc
[Policy] $policy
FolderDescription([string]$guid, [string]$desc) {
$this.path = 'HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FolderDescriptions\' + $guid + '\PropertyBag'
$this.desc = $desc
$prop = Get-ItemProperty -Path $this.path -Name 'ThisPCPolicy' -ErrorAction SilentlyContinue
if ($prop -ne $null) {
$this.policy = $prop.ThisPCPolicy
}
else {
$this.policy = [Policy]::Show
}
}
[string] ToString() {
return $this.desc
}
[void] SetPolicy([Policy]$policy) {
if ($this.policy -ne $policy) {
if (!(Test-Path $this.path)) {
New-Item $this.path -Force
}
Set-ItemProperty -Path $this.path -Name 'ThisPCPolicy' -Value $policy
$this.policy = $policy
[FolderDescription]::dirty = $true
}
# Write-Host "$([FolderDescription]::dirty) $($this.policy) $($this.desc)"
}
}
$icons = @(
[FolderDescription]::new('{31C0DD25-9439-4F12-BF41-7FF4EDA38722}', '「3Dオブジェクト」フォルダのアイコンを表示する'),
[FolderDescription]::new('{b4bfcc3a-db2c-424c-b029-7fe99a87c641}', '「デスクトップ」フォルダのアイコンを表示する'),
[FolderDescription]::new('{7d83ee9b-2244-4e70-b1f5-5393042af1e4}', '「ダウンロード」フォルダのアイコンを表示する'),
[FolderDescription]::new('{f42ee2d3-909f-4907-8871-4c22fc0bf756}', '「ドキュメント」フォルダのアイコンを表示する'),
[FolderDescription]::new('{a0c69a99-21c8-4671-8703-7934162fcf1d}', '「ミュージック」フォルダのアイコンを表示する'),
[FolderDescription]::new('{0ddd015d-b06c-45d5-8c4c-f59713854639}', '「ピクチャ」フォルダのアイコンを表示する'),
[FolderDescription]::new('{35286a68-3c57-41a1-bbb1-0eae73d76c95}', '「ビデオ」フォルダのアイコンを表示する')
)
[FolderDescription]::dirty = $false
$icons | MultiSelection -Initial { $_.policy } -Selected { $_.SetPolicy([policy]::Show) } -Unselected { $_.SetPolicy([policy]::Hide) }
if ([FolderDescription]::dirty) {
Write-Host "設定が変更されました。エクスプローラーを再起動してください。"
}
else {
Write-Host "設定は変更されませんでした。"
}
@uemuraj
Copy link
Author

uemuraj commented Nov 7, 2022

テキストベースの複数選択式メニューを実装してみました。こんな感じになります。

PS> .\FolderIcons.ps1
 [*] 「デスクトップ」フォルダのアイコンを表示する
 [*] 「ダウンロード」フォルダのアイコンを表示する
 [*] 「ドキュメント」フォルダのアイコンを表示する
 [ ] 「ミュージック」フォルダのアイコンを表示する
 [ ] 「ピクチャ」フォルダのアイコンを表示する
 [ ] 「ビデオ」フォルダのアイコンを表示する
設定は変更されませんでした。

@uemuraj
Copy link
Author

uemuraj commented Dec 4, 2022

OneDrive と 3DObject にも対応しておきたいところ。

[HKEY_CLASSES_ROOT\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}]
"System.IsPinnedToNameSpaceTree"=0
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FolderDescriptions\{31C0DD25-9439-4F12-BF41-7FF4EDA38722}]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment