VSCodeの拡張機能が動かなくなった
Visual Studio Codeの拡張機能が動かなくなった。
原因としては markdown-all-in-one という拡張機能がうまくアンインストールできていなかったから。
調査の記録を記事として書きました。

現象
拡張機能を使おうとすると Command 'Live Share: Join Collaboration Session' resulted in an error (command 'liveshare.join not found) と表示されて拡張機能が動作しない。
LiveShareだけかと思ったらその他の拡張機能も同様に開くことができなくなっていた。
調査
拡張機能が存在するか調査
code --list-extentions コマンドでVSCodeに入っている拡張機能一覧を取得する。
ref: Managing Extensions in Visual Studio Code
❯ code --list-extensions 4ops.terraform aws-scripting-guy.cform christian-kohler.path-intellisense CoenraadS.bracket-pair-colorizer Darfka.vbscript DavidAnson.vscode-markdownlint donjayamanne.githistory eamodio.gitlens esbenp.prettier-vscode funkyremi.vscode-google-translate GitHub.vscode-pull-request-github Gruntfuggly.todo-tree hashicorp.terraform hediet.vscode-drawio jebbs.plantuml ms-azuretools.vscode-docker ms-python.python ms-python.vscode-pylance ms-toolsai.jupyter ms-toolsai.jupyter-keymap ms-toolsai.jupyter-renderers ms-vscode-remote.remote-containers ms-vscode-remote.remote-ssh ms-vscode-remote.remote-ssh-edit ms-vscode-remote.remote-wsl ms-vscode-remote.vscode-remote-extensionpack ms-vscode.powershell ms-vsliveshare.vsliveshare ms-vsliveshare.vsliveshare-audio ms-vsliveshare.vsliveshare-pack redhat.java redhat.vscode-commons redhat.vscode-yaml streetsidesoftware.code-spell-checker Tyriar.sort-lines VisualStudioExptTeam.vscodeintellicode vscjava.vscode-java-debug vscjava.vscode-java-dependency vscjava.vscode-java-pack vscjava.vscode-java-test vscjava.vscode-maven
開けなかった拡張機能は存在していることになっている...
❯ ls ~/.vscode/extensions 4ops.terraform-0.2.2 aws-scripting-guy.cform-0.0.24 christian-kohler.path-intellisense-2.6.0 christian-kohler.path-intellisense-2.6.1 coenraads.bracket-pair-colorizer-1.0.62 darfka.vbscript-1.0.4 davidanson.vscode-markdownlint-0.45.0 donjayamanne.githistory-0.6.19 eamodio.gitlens-11.7.0 esbenp.prettier-vscode-9.1.0 funkyremi.vscode-google-translate-1.4.13 github.vscode-pull-request-github-0.34.3 gruntfuggly.todo-tree-0.0.214 gruntfuggly.todo-tree-0.0.215 hashicorp.terraform-2.18.0 hashicorp.terraform-2.19.0 hediet.vscode-drawio-1.6.4 jebbs.plantuml-2.17.0 jebbs.plantuml-2.17.1 jebbs.plantuml-2.17.2 ms-azuretools.vscode-docker-1.18.0 ms-azuretools.vscode-docker-1.19.0 ms-python.python-2021.12.1559732655 ms-python.vscode-pylance-2021.11.0 ms-python.vscode-pylance-2022.1.0 ms-python.vscode-pylance-2022.1.1 ms-toolsai.jupyter-2021.10.1001414422 ms-toolsai.jupyter-2021.11.1001550889 ms-toolsai.jupyter-2021.9.1101343141 ms-toolsai.jupyter-keymap-1.0.0 ms-toolsai.jupyter-renderers-1.0.4 ms-vscode-remote.remote-containers-0.202.5 ms-vscode-remote.remote-containers-0.209.6 ms-vscode-remote.remote-ssh-0.70.0 ms-vscode-remote.remote-ssh-edit-0.70.0 ms-vscode-remote.remote-wsl-0.63.13 ms-vscode-remote.vscode-remote-extensionpack-0.21.0 ms-vscode.powershell-2021.12.0 ms-vsliveshare.vsliveshare-1.0.5065 ms-vsliveshare.vsliveshare-1.0.5242 ms-vsliveshare.vsliveshare-1.0.5273 ms-vsliveshare.vsliveshare-audio-0.1.91 ms-vsliveshare.vsliveshare-pack-0.4.0 redhat.java-1.2.0 redhat.vscode-commons-0.0.6 redhat.vscode-yaml-1.2.2 redhat.vscode-yaml-1.3.0 streetsidesoftware.code-spell-checker-2.0.14 streetsidesoftware.code-spell-checker-2.1.3 streetsidesoftware.code-spell-checker-2.1.4 tyriar.sort-lines-1.9.1 visualstudioexptteam.vscodeintellicode-1.2.15 vscjava.vscode-java-debug-0.37.0 vscjava.vscode-java-dependency-0.18.9 vscjava.vscode-java-pack-0.20.0 vscjava.vscode-java-test-0.33.1 vscjava.vscode-maven-0.34.2 yzhang.markdown-all-in-one-3.4.0
一覧表示してもわかりにくいので表示のdiffを取ります。
❯ diff -i <(ls ~/.vscode/extensions | sed 's/-[0-9].*$//g' | uniq) <(code --list-extensions) 42d41 < yzhang.markdown-all-in-one
なんかフォルダだけに残っている拡張機能がありますね👀
コマンドの解説
diffコマンド
対象のファイルの差分を出力します。
比較するファイルとしてコマンドの実行結果を渡すには <() を用いて名前付きパイプとするとあたかもファイルのように比較することができます。
まだ diff -i で大文字と小文字の変化を無視することができます。
lsとsedコマンド
みんなの強い味方 sed
-[数字] を空白に置換することで vscode/extentions の表示に含まれるバージョン情報を削除しています。
ls ~/.vscode/extensions | sed 's/-[0-9].*$//g'
~ ❯ ls ~/.vscode/extensions | tail -n 3 vscjava.vscode-maven-0.34.2 yzhang.markdown-all-in-one-3.4.0 ~ ❯ ls ~/.vscode/extensions | sed 's/-[0-9].*$//g' | tail -n 3 vscjava.vscode-java-test vscjava.vscode-maven yzhang.markdown-all-in-one
uniq コマンド
表示行で重複するものを消せる。 複数バージョンの拡張機能があると複数フォルダが表示されて嶋う。uniq コマンドで重複を消している
検証
ファイルはあるけどVSCode側にインストールされていない拡張機能を削除。
❯ rm -rf ~/.vscode/extensions/yzhang.markdown-all-in-one-3.4.0
うまく動くようになった!

どうやら Markdown all in one を過去にアンインストールした際にファイルが残り続けてしまったことが原因らしい。
探してみるとネット上にもちらほらそんな記事が存在した。
最後に
無事に拡張機能が使えるようになってよかったです。 最近読んだシェルノック本がとても役立ちました。
いままでsedでどうやるんだっけ...とか悩むことがありましたがその頻度も減ってきていい感じです。 おすすめ。
Windowsイベントログ解析ツール「Hayabusa」を使ってみる
こんにちは、いちび( @itiB_S144 )です。
2021年12月25日にWindowsイベントログ解析ツールとして「Hayabusa」がリリースされました🎉
Hayabusaは事前に作成したルールに則ってWindowsイベントログを調査し、インシデントや何かしらのイベントが発生していないか高速に検知することができるツールです。 私も開発を微力ながらお手伝いさせていただきました。 本記事では多くの方にHayabusaを触っていただきたいため、簡単な使い方を紹介していきます。
github.comWe just released two Windows event log analysis tools: Hayabusa and WELA: https://t.co/nFHxSgUl2q #yamasec
— Yamato Security Tools (@SecurityYamato) 2021年12月25日
詳細なHayabusaの実装についてはコミッターのKazuminさんの記事が参考になります、 ぜひご参照ください!
Hayabusaとは
HayabusaはWindowsイベントログの解析ツールです。 事前に作成したルールに則って解析を行い、ルールに引っかかるものがあれば検知します。
Hayabusaは、日本のYamato Securityグループによって作られたWindowsイベントログのファストフォレンジックタイムライン生成およびスレットハンティングツールです。
hayabusa/README-Japanese.md at main · Yamato-Security/hayabusa · GitHub
ルールは独自に作成することも可能ですが、1000以上のルールがプリセットとして用意されており、手軽に試すことができます。 また日本のコミュニティが作っているため日本語のREADMEが充実しています。英語が苦手な方でも安心
ルールの例
- 管理者権限でだれかがログインした
- WindowsDefenderのアラートが鳴っている
- PreFetchファイルが削除された
Hayabusaリポジトリの中には独自に作られたルールと多くの研究者が作成したルールである Sigma をベースに変換したルールが配置されています。 上にあげた例だけでなく、マルウェア検知など様々なルールが用意されています。 自分でルールを作るのが難しいという方でも十二分にHayabusaを利用することができます。
Hayabusaを使ってみる
以下に用意されたサンプルWindowsイベントログファイルに対してHayabusaを実行してみます。 ルールファイルはHayabusaで用意されたものを用います。 github.com
環境
- Windows 10 Education
- hayabusa-1.0.0
手順
1. GitHubから必要なファイルを入手
Hayabusaの実行ファイルとサンプルWindowsイベントログファイルを取得します。
- Hayabusa実行ファイル
- サンプルWindowsイベントログファイル
Windows環境なので hayabusa-1.0.0-windows-x64-evtx-0.7.2.zip をダウンロードしました。evtx以降の 0.6.7 と 0.7.2 の違いは中で使用しているライブラリのバージョンの違いです。とりあえず新しいほうを選んでいます。

ファイルを解凍して準備OKです。
2. フォルダの確認
基本的に変更が発生するのは config フォルダになります。
大量発生してログを埋め尽くすようなルールをミュートしたり等々の設定ができます。
ひとまず今回はデフォルトのままで進めます。
├── hayabusa-1.0.0-windows-x64-evtx-0.7.2
│ ├── README.md
│ ├── hayabusa.exe
│ ├── config // 設定ファイル
│ ├── doc // ドキュメントたち
│ ├── logs // hayabusa.exeの実行ログ
│ ├── rules // 検知ルールファイルたち
│ ├── sample-results
│ └── tools
└── hayabusa-sample-evtx-main // サンプルイベントファイルたち
├── DeepBlueCLI
├── EVTX-ATTACK-SAMPLES
├── EVTX-to-MITRE-Attack
├── README.md
└── YamatoSecurity
3. Hayabusaの実行
コマンドプロンプトからHayabusaを起動します。
エクスプローラーでHayabusaフォルダに移動し、バーに cmd と入力することで簡単に開くことができます。

オプションをなにもつけずに hayabusa.exe を実行するとヘルプが出てきます。

ファイルに対してHayabusaを実行
hayabusa-sample-evtx に用意されたサンプルのWindowsイベントログファイル(.evtx)に対してHayabusaを実行します。
>hayabusa.exe -f <検査対象WIndowsイベントログ.evtx>

検知した内容が表示されたのち、サマリが表示されます。
デフォルトのHayabusaが使用しているルールは /rules フォルダ下に配置されたすべてのルールです。
オプションから使用するルールを指定することも可能です。
フォルダに対してHayabusaを実行
windowsイベントファイルを置いたフォルダに対してまとめてHayabusaを実行することができます。
>hayabusa.exe -d ..\hayabusa-sample-evtx-main
その他
基本的な使い方はREADMEにすべて書かれています。 検出結果のファイルへの出力方法等は以下に記載されていますので参考にしてください。
hayabusa/README-Japanese.md at main · Yamato-Security/hayabusa · GitHub
自分のWindowsに対してHayabusa実行
サンプルのWindowsイベントログファイルにHayabusaを実行した後は自分のWindowsに対して実行してみたくなりますね? 早速試していきましょう。
新規Windowsユーザの作成
今回はログに残る動作として新たなユーザをWindowsに追加します。
設定 → アカウント → 他のユーザ からユーザを追加します。

ログの取得
Windowsのイベントログファイルは C:\Windows\System32\winevt\Logs 下に保存されます。
管理者権限が必要となるため Hayabusa を管理者権限のあるコマンドプロンプトで開くかログファイルを管理者権限のいらないフォルダ下にコピーしましょう。
ユーザ追加のログは Security.evtx に保存されます。

Hayabusaで調査する
コピーした Security.evtx に対してHayabusaをかけてみました。
User: test が作られたことを検知できていることがわかります。

オプション -o をつけるとCSVファイルに検知結果を出力することができます。
>hayabusa.exe -f ..\Security.evtx -o detect.csv
detect.csv
Timestamp,Computer,EventID,Level,RuleTitle,Details,RulePath,FilePath 2021-12-31 19:38:37.370 +09:00,DESKTOP-ITIB,4728,low,User added to local security group,User: itib : Group: なし : LogonID: 0x4a111111,rules\hayabusa\default\alerts\Security\4728-AccountManipulation_UserAddedToLocalSecurityGroup.yml,..\Security.evtx 2021-12-31 19:38:37.370 +09:00,DESKTOP-ITIB,4728,medium,User added to global security group,User: itib : Group: なし : LogonID: 0x4a111111,rules\hayabusa\default\alerts\Security\4728_AccountManipulation_UserAddedToGlobalSecurityGroup.yml,..\Security.evtx 2021-12-31 19:38:37.372 +09:00,DESKTOP-ITIB,4720,medium,Local user account created,User: test : SID: S-1-1-11-111111111-1111111111-1111111111-1111,rules\hayabusa\default\alerts\Security\4720_CreateAccount-LocalAccount_UserAccountCreated.yml,..\Security.evtx
csvには検知したルールファイルへのパスが表示されています。
ルールファイルを見てみる
Hayabusaで調査するで検知したイベントログとルールファイルを見てみましょう。
Security.evtxをイベントビューアで開き、検索を駆使して検知したイベントを見つけました。
イベントログの EventID が 4720、ChannelがSecurity、作られたTargetUserNameがtestであることがわかります。後々のためにXML形式で見ています。

上記イベントを検知した先ほどルールファイルは 4720_CreateAccount-LocalAccount_UserAccountCreated.yml でした。
author: Eric Conrad, Yamato Security creation_date: 2020/11/08 uodated_date: 2021/12/22 title: Local user account created title_jp: ローカルユーザアカウントが作成された details: 'User: %TargetUserName% : SID: %TargetSid%' details_jp: 'ユーザ名: %TargetUserName% : SID: %TargetSid%' description: A local user account was created. description_jp: ローカルユーザアカウントが作成された. id: 13edce80-2b02-4469-8de4-a3e37271dcdb level: medium status: stable detection: selection: Channel: Security EventID: 4720 filter: TargetUserName|endswith: "$" #Filter out machine/computer accounts condition: selection and not filter falsepositives: - system administrator tags: - attack.persistence - attack.11136.001 references: - https://attack.mitre.org/techniques/T1136/001/ sample-evtx: ./sample-evtx/DeepBlueCLI/new-user-security.evtx logsource: default ruletype: Hayabusa
detection下に書かれた条件で検知が行われます。
Channel が Security AND EventID が 4720 であり、filter にマッチしない条件がこのルールで検知されるようです。
検知した場合は title: Local user account created と details: 'User: %TargetUserName% : SID: %TargetSid%' の %~% が埋められた文字列が検知結果として表示されています。
詳細なルールの書き方はこれまたREADMEに詳しく書かれていますので参考にしてください。
hayabusa/AboutRuleCreation-Japanese.md at main · Yamato-Security/hayabusa · GitHub
最後に
ここまで読んでいただきありがとうございました。
簡単なHayabusaの使い方を紹介させていただきました。 Hayabusa、面白そう!触ってみたいと思っていただけたら幸いです。
HayabusaはOSSとして大和セキュリティが開発しています。 Hayabusaの開発気になる、バグ見つけた等あればGithubのissueや下記ConnpassのSlackからコンタクトお願いします。
それではよいWindowsログ解析ライフを!
Windowsの音声出力先を変えるショートカット作成
本記事は ZOZO Advent Calendar 2021 の10日目の記事です。
みなさん在宅ワークしていますか? 自分はフルリモートの会社で働いているためどれだけ在宅環境をよくできるか日々考えています。
本記事では在宅ワークの際に手間だと感じていた 「パソコンの音声出力先変更」をショートカット1つでできるようにした方法を解説します。
どのように調べ、実現までもっていったか、参考になれば幸いです。
やりたいこと
パソコンで音楽を流したり好きなラジオ、配信を聞きながらテンションを上げて作業している方は多いと思います。 お昼時など席を離れた際にわざわざスマホに切り替えて、とかするのは大変ですよね?
我が家では普段の作業時には机の上のスピーカ、キッチンに移動したらおいてあるAlexaからBluetooth接続で音楽を再生させていました。
スピーカボタンを押してデバイスの選択という流れで音声の出力先を切り替えています。

この作業がなかなかに手間。
移動開始前に数ステップある作業は嬉しくない。
理想は1クリックで移動可能、
なんなら移動したことを検知して勝手にスピーカを切り替えてほしい。
ということで本記事では「1クリックで音声出力先を切り替えられるようなショートカットを作成する」を目標に調査、実装を行っていきます。
調査
Windowsがどのようにデフォルトの音声出力先を決めているのか調査します。 どうやって設定しているかがわかれば対応したコードを書いて実行できるはず!
Windows APIの調査
Windowsの多くの動作はAPIを用いて操作することができます。 「Windows API インデックス」を漁っていきます。 音声出力先の設定に関わりそうなドキュメントとしては「Windows Core Audio API について」がありました。
コア オーディオ API は次のとおりです。
・マルチメディアデバイス(MMDevice)API。クライアントは、このAPIを使用して、システム内のオーディオエンドポイントデバイスを列挙します。
・...
列挙してくれるだけらしい🤔
フォーラムとかを見るとデバイスの切り替えのAPIは提供されていないように見えます。
ref: Programatically setting the default playback device (and recording device)
どこかのレジストリに格納されているのでは?
WIndowsの設定情報はレジストリに格納される。 当然音声出力先の情報もあるはず。
レジストリエディタで探すと \HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Render\ 下に接続されたデバイスらしきデータが見つかりました。

音声出力先を変更した際にどこの値が変化するか観察してみると出力先に設定したタイミングでUUID({xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}形式の値)下に含まれる Level: 0 ~ Level: 2 の値が変化するようです。
- 値は出力に設定されるたびに+nされる
- 別の値が出力先になっても値は変化しない
- 足し算される値は期間を開けると大きくなる
ここから時間等でLevelに代入される値が決まっており、 値が最新のもの が音声出力先として使われていると考えることができます。

レジストリの値は手動で編集することができるため右クリックで修正してみました。
再生先になっていないデバイスの値を現在の音声出力先となっているデバイスの値より大きくすれば出力先が変更されると予測していました。
とりあえず Level: 2 の値を +1 してみました。
| 変更前 | 変更後 | |
|---|---|---|
| Level: 0 | 0x000003cc | 0x000003cc |
| Level: 1 | 0x000003cc | 0x000003cc |
| Level: 2 | 0x0000020d | 0x0000020e |
値を変更した直後からWindows の右下サウンドマークで表示される出力先には値を大きくしたデバイスが表示されるようになったものの 音声の出力先はいままでの出力先のままという状態になりました。

デスクトップの表示だけされても意味がないんだ...
既存実装調査
ここまでで自力では手詰まりだったのでGithubで先人たちの書いた実装を調べます。
Audioやいままでの調査で出てきたMMDevices等のキーワードたちでGithubを調べます。検索してみるとやりたいことを実装しているコードが何個も出てきます。以下は実装の際に大きく参考にしたリポジトリです。
先人は偉大。
気合で読んで以下のような流れで音声出力先を変更していることがわかりました。
- IPolicyConfig インタフェースを実装したPolicyConfigClientを作成
PolicyConfigClientにIPolicyConfigに含まれるSetDefaultDevice()を実装SetDefaultDevice()にデバイスのUUIDとシステムがオーディオエンドポイントデバイスに割り当てた役割を示すERoleを渡して呼び出す- 出力先が変更される
実装する
先人たちのツールを使えば簡単ですが自分でもいろいろいじりたいと思い手を動かしていきます。実装する内容は以下の2つです。
- 出力先として利用可能なデバイス一覧を表示
- 音声出力先の切り替え
先人たちのコードが C# で書かれていましたが自分は C# の知見があまりないのできっとPowerShellならWindows 関連なんとかなるでしょ!という安直な考えでPowerShellで実装しました。
出力先として利用可能なデバイス一覧を表示
オーディオ関連のレジストリを調査した際に機器情報が格納されている場所がわかりました。指定した箇所のレジストリ内容を出力することでデバイス名を取得します。
$regRoot = "HKLM:\Software\Microsoft\" function Get-Devices { $regKey = $regRoot + "\Windows\CurrentVersion\MMDevices\Audio\Render\" Write-Output "Active Sound devices:" Get-ChildItem $regKey | Where-Object { $_.GetValue("DeviceState") -eq 1} | Foreach-Object { $subKey = $_.OpenSubKey("Properties") Write-Output (" " + $subKey.GetValue("{a45c254e-df1c-4efd-8020-67d146a850e0},2")) Write-Output (" " + $_.Name.Substring($_.Name.LastIndexOf("\"))) } } Get-Devices
実行すると以下のようにデバイス名とUUIDが表示されます。
PS > .\deviceList.ps1 Active Sound devices: スピーカー \{476a4519-c338-4f9e-9746-294cd6429136} 1-2 \{4c884bad-d966-441a-b1f9-4ec0fced2fbc} 3-4 \{cd21a3a3-061e-4064-94a6-f5769eda2979} ヘッドホン \{ee3cf230-46d3-4043-8fc2-7cd4dff984b0} Digital Audio (S/PDIF) \{fa27ad22-6853-430a-b1e5-10b83f01dbbb}
音声出力先の切り替え
ここは先人たちのC#で書かれたコードをもとに実装しました。
あまりC#の知見がない + デバイス一覧取得をpowershellで書いたためできればpowershellで完結させたい、 と思っていたところpowershellは変数として与えたC#のコードを実行できるらしい。宇宙感じた。
必要となるERole, IPolicyConfig, PolicyConfigClientを実装しPowershellから呼び出すようにします。
$cSharpSourceCode = @" using System; using System.Runtime.InteropServices; using System.Collections.Generic; internal enum ERole : uint { eConsole = 0, eMultimedia = 1, eCommunications = 2, ERole_enum_count = 3 } [Guid("F8679F50-850A-41CF-9C72-430F290290C8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IPolicyConfig { [PreserveSig] int GetMixFormat(); [PreserveSig] int GetDeviceFormat(); [PreserveSig] int ResetDeviceFormat(); [PreserveSig] int SetDeviceFormat(); [PreserveSig] int GetProcessingPeriod(); [PreserveSig] int SetProcessingPeriod(); [PreserveSig] int GetShareMode(); [PreserveSig] int SetShareMode(); [PreserveSig] int GetPropertyValue(); [PreserveSig] int SetPropertyValue(); [PreserveSig] int SetDefaultEndpoint( [In] [MarshalAs(UnmanagedType.LPWStr)] string deviceId, [In] [MarshalAs(UnmanagedType.U4)] ERole role); [PreserveSig] int SetEndpointVisibility(); } [ComImport, Guid("870AF99C-171D-4F9E-AF0D-E63DF40C2BC9")] internal class _CPolicyConfigClient { } public class PolicyConfigClient { public static int SetDefaultDevice(string deviceID) { IPolicyConfig _policyConfigClient = (new _CPolicyConfigClient() as IPolicyConfig); try { Marshal.ThrowExceptionForHR(_policyConfigClient.SetDefaultEndpoint(deviceID, ERole.eConsole)); Marshal.ThrowExceptionForHR(_policyConfigClient.SetDefaultEndpoint(deviceID, ERole.eMultimedia)); Marshal.ThrowExceptionForHR(_policyConfigClient.SetDefaultEndpoint(deviceID, ERole.eCommunications)); return 0; } catch { return 1; } } } "@ add-type -TypeDefinition $cSharpSourceCode function Set-DefaultAudioDevice { Param ( [parameter(Mandatory=$true)] [string[]] $deviceId ) If ([PolicyConfigClient]::SetDefaultDevice("{0.0.0.00000000}.$deviceId") -eq 0) { Write-Host "SUCCESS: The default audio device has been set." } Else { Write-Host "ERROR: There has been a problem setting the default audio device." } } $id = $args[0] Set-DefaultAudioDevice $id
1つ目の引数として音声出力先に設定したいデバイスのUUIDを渡すとSetDefaultDeviceが実行され音声出力先を変更することができました。
PS > .\deviceSet.ps1 "{4c884bad-d966-441a-b1f9-4ec0fced2fbc}" SUCCESS: The default audio device has been set.
スクリプト実行用のショートカット作成
作成したPowerShellコードを呼び出すショートカットを作成します。 Windowsのショートカットには引数を与えて作ることができるので出力先に対応したショートカットをデスクトップに作成します。
ショートカットを作成し、そのプロパティからリンク先を powershell.exe <作成したdeviceSet.ps1へのパス> <設定対象のUUID> に編集します。
サンプル: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe C:\Users\guest\deviceSet.ps1 "{4c884bad-d966-441a-b1f9-4ec0fced2fbc}"

出来上がったショートカットをデスクトップに置くことで以下のように音声出力先を1クリックで変更できるようになりました。 自分の環境ではアイコン画像も変えてわかりやすくしました。

おわりに
目標だった「1クリックでWindowsの音声出力先を変更する」を達成することができました。
手軽に再生先を変えられるようになっただけでなく、 Windowsの音声出力設定方法やシステムについて詳しくなれた、 PowerShellがC#のコードを読みだせることを知れた点で挑戦してみてよかったと思います。
つぎはPowerShellから別の言語に書き換えたり、人の部屋移動を検知してこのショートカットを叩かせたりしたいです。
二分木(Binary Search Tree)の実装 その1
概要
シンプルな二分木をGolangで実装していきます。 二分木の動作は以下のURLがビジュアル化されていてわかりやすいです。
Binary Search Tree Visualization
まずは二分木のベースとして値の挿入をして木を作成し、 見つけたい値が木に含まれているかを判定する関数を作成します。
実装
木とノードの定義
type Node struct { Value int // ノードの持つ値 Left *Node // 左側ノードへのポインタ Right *Node // 右側ノードへのポインタ } // 二分木として持つのはルートノードのみ // ノードにアクセスするのはすべてルートからたどる type Tree struct { Root *Node }
代入処理
// TreeにNodeを加える func (t *Tree) Insert(insertValue int) { if t.Root == nil { // 初回のNodeだった場合はTreeのRootとしてNodeを設定する // t.root = CreateNode(insertValue) t.Root = &Node{Value: insertValue} } else { parentNode := t.Root for { if insertValue >= parentNode.Value { // 右のノードを確認 if parentNode.Right != nil { // ノードが存在するならば移動 parentNode = parentNode.Right } else { // ノードがまだ無ければノードを配置する parentNode.Right = &Node{Value: insertValue} break } } else { // 左のノードを確認して同様に代入OR移動 if parentNode.Left != nil { parentNode = parentNode.Left } else { parentNode.Left = &Node{Value: insertValue} break } } } } }
テストの作成
値を代入して正しい位置にノードがあるかを判定するテストコードを作成し、正しく処理ができているか確認します。
ここでは 4, 2, 7, 6 の順に代入して目的の木ができているかを確認します。

func TestCreateTree(t *testing.T) { var tree binary_search_tree.Tree tree.Insert(4) tree.Insert(2) tree.Insert(7) tree.Insert(6) if tree.Root.Value != 4 { t.Error("Failed") } if tree.Root.Left.Value != 2 { t.Error("Failed") } if tree.Root.Right.Value != 7 { t.Error("Failed") } if tree.Root.Right.Left.Value != 6 { t.Error("Failed") } if tree.Root.Right.Right != nil { t.Error("Failed") } }
ディレクトリ構成
project ├ binary_search_tree │ ├ binary_search_tree.go │ └ binary_search_tree_test.go └ go.mod
binary_search_tree.go
package binary_search_tree type Node struct { Value int Left *Node Right *Node } // NodeたちにアクセスするのはすべてRootから // BinarySearchTreeとして知っているのはRootの場所のみ type Tree struct { Root *Node } // TreeにNodeを加える func (t *Tree) Insert(insertValue int) { if t.Root == nil { // 初回のNodeだった場合はTreeのRootとしてNodeを設定する // t.root = CreateNode(insertValue) t.Root = &Node{Value: insertValue} } else { parentNode := t.Root for { if insertValue >= parentNode.Value { // 右のノードを確認 if parentNode.Right != nil { // ノードが存在するならば移動 parentNode = parentNode.Right } else { // ノードがまだ無ければノードを配置する parentNode.Right = &Node{Value: insertValue} break } } else { // 左のノードを確認して同様に代入OR移動 if parentNode.Left != nil { parentNode = parentNode.Left } else { parentNode.Left = &Node{Value: insertValue} break } } } } }
binary_search_tree_test.go
package binary_search_tree_test import ( "testing" "github.com/itiB/project/binary_search_tree" ) func TestCreateTree(t *testing.T) { var tree binary_search_tree.Tree tree.Insert(4) tree.Insert(2) tree.Insert(7) tree.Insert(6) if tree.Root.Value != 4 { t.Error("Failed") } if tree.Root.Left.Value != 2 { t.Error("Failed") } if tree.Root.Right.Value != 7 { t.Error("Failed") } if tree.Root.Right.Left.Value != 6 { t.Error("Failed") } if tree.Root.Right.Right != nil { t.Error("Failed") } }
go.mod
module github.com/itiB/project go 1.16
テスト結果正常に木が作成できていることがわかりました。
❯ go test ./binary_search_tree ok github.com/itiB/project/binary_search_tree 0.004s
検索したい値が木に含まれているか判定
検索対象の値が木に含まれているか調べるには代入する場所を探すのと同様に木を探索していって一致する値が含まれているかを調べることで実装できます。
func (tree *Tree) Contains(findValue int) bool { // そもそも木がなければ含まれていない if tree.Root == nil { return false } cursor := tree.Root // 調べているノードを指す for { // ノードの値が検索対象の値なら発見 if cursor.Value == findValue { return true } else { // ノードを移動する処理 // もし進むべき方向にノードがないならば値は含まれていないとしてfalse if findValue >= cursor.Value { if cursor.Right != nil { cursor = cursor.Right } else { return false } } else { if cursor.Left != nil { cursor = cursor.Left } else { return false } } } } }
テストの作成
木を作成し、代入した値が含まれているかのテストを記述します。
func TestFindTree(t *testing.T) { var tree binary_search_tree.Tree tree.Insert(4) tree.Insert(2) tree.Insert(7) tree.Insert(6) tree.Insert(-5) if !tree.Contains(4) { t.Errorf("Failed") } if !tree.Contains(6) { t.Errorf("Failed") } if !tree.Contains(-5) { t.Errorf("Failed") } if tree.Contains(5) { t.Errorf("Failed") } if tree.Contains(500000000000) { t.Errorf("Failed") } }
❯ go test ./binary_search_tree ok github.com/itiB/project/binary_search_tree 0.004s
まとめ
二分木のベースとなる処理を作成することができました。 次は削除処理を作成します。
Base64デコーダーを作る
本記事は以前筆者のqiitaに投稿していた記事を移動させたものです。
とあるCrackmeでcustom_base64なるものでエンコードされた文字列が出てきた...
Flagを手に入れるためにはこれをデコードして元の文字列を見つけなきゃいけない.
custom_base64とはなんなのか...答えを見つけるために,我々はアマゾンの奥地へと...
概要
Base64の仕組みの中で000000 ~ 111111を文字に置き換えた辞書が存在する.
通常のBase64では順番に ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ をあてはめた辞書が使われている.
これを指定した辞書に入れ替えたものがcustom_base64関数の中身であった.
Base64を実装する記事を参考に本記事ではPythonでデコーダーを実装する.
Base64の仕組み
エンコード
大まかにBase64のエンコードの処理を確認します.詳しくは他サイトを参照.
- 変更したい文字列(ASCII)をバイナリ(2進数)に変換
- バイナリを6bitづつに分割
- 分割した際に最後が6bitより少なくなるため,6bitになるように0を追加する
- 変換表を用いて6bitを文字に変換
- 4biteずつBase64では出力するために文字数が4の倍数文字になるよう"="を付け足す
- base64の文字列の完成!!
デコード
エンコードの仕組みがわかればデコードは簡単!基本的には逆の手順を踏むだけ!
- 付け足された"="を削除
SG9nZUhvZ2U=→SG9nZUhvZ2U
- 変換表を用いて文字をバイナリに変換してつなげる.
SG9nZUhvZ2U→010010 000110 111101 100111 011001 010100 100001 101111 011001 110110 010100
- バイナリを8bitずつに分割,エンコード3. で付け足された0が余るのでそれらを削除
01001000 01101111 01100111 01100101 01001000 01101111 01100111 01100101 00
- 2進数bitをASCIIに変換
01001000 → H 01101111 → o 01100111 → g 01100101 → e 01001000 → H 01101111 → o 01100111 → g 01100101 → e
- デコード完了!
プログラムにしてみる
import sys
import argparse
BYTE_SIZE = 8
# 000000 -> 111111まで1文字ずつ辞書型リストを作成する関数
def makeDict(base64Dict_seed):
dictionary = {}
for i in range(0, 64):
dictionary[format(i, '06b')] = base64Dict_seed[i]
return dictionary
# 文字列s をn文字で区切ってリスト化する関数
def split(string, n):
split_list = []
for i in range(0, len(string), n):
split_list.append(string[i:i+n])
return split_list
# 文字列がn文字なかったらn文字になるように`c`を足す
def fillBlank(s, n, c):
mod = len(s) % n
if mod == 0:
return s
else:
margin = n - mod
return s + c * margin
# 辞書の値を渡すと辞書のキーを返す
def getValue(key, items):
for v in items.items():
# print(v[1])
if v[1] == key:
# print(v)
return v[0]
return ''
def main():
# -kをつけるとカスタム辞書を入力できる
parser = argparse.ArgumentParser(
description='custom Base64 Decoder')
parser.add_argument('-k', '--key', help="Use custom Seed to encrypt in base64 ", \
default="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
parser.add_argument('text', help='base text')
args = parser.parse_args()
# 0. 辞書を作る
base64Dict = makeDict(args.key)
# 1. '='をはずす
text = args.text.replace("=", '')
binStr = ""
# 2. 変換表を用いて文字をバイナリに変換してつなげる.
for i in text:
binStr += getValue(i, base64Dict)
# 3. バイナリを8bitずつに分割,エンコード3. で付け足された0が余るのでそれらを削除
splitCount = 8
s = split(binStr, splitCount)
if (len(s[-1]) != 8):
s.pop(-1)
# 4. 2進数bitをASCIIに変換
result =""
for c in s:
print(c + " → " + chr(int(c, 2)))
result += chr(int(c, 2))
print(result)
if __name__ == "__main__":
main()
使い方
$ python3 customBase64Decoder.py <Base64テキスト>
$ python3 customBase64Decoder.py -k <Custom辞書> <Base64テキスト>
$ python3 customBase64Decoder.py SG9nZUhvZ2U=
$ python3 customBase64Decoder.py -k xEPOKnvADqeG0m1VkZ47CM653jrtbzLsTc2ypoYUSWJ9ludQig+awf8XF/RNHBhI 4vBUjCcQj8C= HogeHoge
まとめ
Base64完全に理解した. これでオリジナルBase64つくって秘密の通信ができちゃうね,やったね
サンプルコードはGitHubに置いてあります
参考文献
base64ってなんぞ??理解のために実装してみた - qiita https://qiita.com/PlanetMeron/items/2905e2d0aa7fe46a36d41
M5StickCを動かしてみる
本記事は筆者が以前Qiitaに投稿していた記事を移動させたものです。
とりあえず動かせるとこまでやりました.
環境
- Windows10
- M5StickCがある
環境つくるよ
必要なものをインストール
- Arduino IDE
https://www.arduino.cc/en/Main/Software - USB to Serial Driver
https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/drivers/CP210x_VCP_Windows.zip
Arduino IDEはサイトに飛んで"Download the Arduino IDE"より,対応するものをダウンロードしてインストールしてください.
USB to Serial Driverはリンクをクリックするとzipがダウンロードされます.
解凍すると中にいくつかのファイルがあると思います.対応するexeを選んで実行してください.
| バージョン | インストーラ |
|---|---|
| Windows10 32ビット版 | CP210xVCPInstaller_x86_v6.7.0.0.exe |
| Windows10 64ビット版 | CP210xVCPInstaller_x64_v6.7.0.0.exe |
| Windows7 | CP210xVCPInstaller_Win7_v5.40.24.exe |
うまくUSB to Serial Driverが入ったか実際にM5StickCをつないで確認していきます.
- . M5StickCをUSBで接続,
- . Windowsのデバイスマネージャを起動
- . ポートの中にUSB Serial Portが現れるはずです.(COM*)はUSBを刺したポート等で変わると思います.

Arduino IDEの設定
Arduino IDEを開いて実際にM5StickCを動かせるように準備していきます.
- . "ファイル -> 環境設定" を開く
- . "追加ボードマネージャのURL" に
https://dl.espressif.com/dl/package_esp32_index.jsonを入力してOK - . "ツール -> ボード"Ard...." -> ボードマネージャ" を開く
- . 検索バーで"esp32"を検索
- . でてきたのをインストールしたのち
閉じる
- . "スケッチ -> ライブラリをインクルード -> ライブラリを管理" を開く
- . 検索バーで
m5stickを検索,インストールしたのち閉じる
- . "ツール -> ボード -> M5Stick-C" を選ぶ
- . ツールのなかにボード情報とかが表示されるようになった

テストプログラムを動かしてみる!
"ファイル -> スケッチ例 -> M5StickC" のなかに様々なテストプログラムがあるので好きなものを選んでください.
ファイルとかの下にある右向きの矢印を押すとプログラムがコンパイルされ転送されます!
まとめ
かなりはやくここまで来れました. テストプログラムをたくさん用意してくれているのでそれで遊んでるだけでも結構たのしいです. こっからいろいろプログラム頑張って書いていきます. また気が向いたら記事にします.
言いたいこと等あれば以下まで Twitter: https://twitter.com/itiB_S144
参考記事
いろいろとM5StickCについて検証してくださっているわかりやすい記事様↓↓ Lang-ship: https://lang-ship.com/blog/

