Windows の npx で NOENT エラーが出る
Windows 環境で 公式サイトからダウンロードしたインストーラーを使って Node.js をインストールした後に npx を使うとエラーが出ました

no such file or directory

Sandbox 下で Node.js だけをインストールして試すと再現します
バージョンは LTS の 20 系です

npm ERR! code ENOENT
npm ERR! syscall lstat
npm ERR! path C:\Users\WDAGUtilityAccount\AppData\Roaming\npm
npm ERR! errno -4058
npm ERR! enoent ENOENT: no such file or directory, lstat 'C:\Users\WDAGUtilityAccount\AppData\Roaming\npm'
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent

メッセージのまま AppData\Roaming\npm が無いらしいのですが 無いなら作って欲しいのに作ってくれないみたいです
手動で作ってもいいですが適当になにかのパッケージを npm でグローバルインストールすると作られます

npm -g i (適当なパッケージ名)
ネットで見かける Windows Sandbox を Home Edition で使う方法
Windows Sandbox を使いたいことがよくあるのですが その時使ってる PC が Pro じゃないこともあります
公式ドキュメントでは Home エディションはサポートしてないと書かれています
ただ ググると Home エディションでも有効化するという bat ファイルが色々出てきます
サイトはいくつも出てきますが bat ファイルの中身は同じみたいです

怪しげなファイルをインストールするものだったり 海賊版的な方法だったりするのかと不安もあるので中身を見てみました
長い割にほとんどが管理者権限で動かすための部分だったりで実質は以下の部分だけでした

dir /b %SystemRoot%\servicing\Packages\*Containers*.mum >sandbox.txt
for /f %%i in ('findstr /i . sandbox.txt 2^>nul') do dism /online /norestart /add-package:"%SystemRoot%\servicing\Packages\%%i"
Dism /online /enable-feature /featurename:Containers-DisposableClientVM /LimitAccess /ALL

パッケージの追加もパッケージ名はローカルにあるものから作ってますし外部からの取得はしてなさそうです
これだけで動くなら正規の方法のようです
ただ問題起きたら影響が大きそうなので事前に壊れてもいい PC で試したいので実行はまた今度にします



ちなみに 1, 2 行目でやってることは

C:\Windows\servicing\Packages\ 内の Containers を含む .mum ファイルすべてに対して

dism /online /norestart /add-package:***

を実行しています
*** のところに .mum ファイルのフルパスが入ります

一旦ファイルに出力してますが 特別な意味はなさそうです
findstr を使ってますが findstr は正規表現で検索するコマンドで 検索条件が「.」なので全件に一致します
空行は無視して 1 件ごと取得するために使ってそうです
作ったファイルもすぐに消しています

やってることは PowerShell のこれと同じはず

$items = dir C:\Windows\servicing\Packages\*Containers*.mum
foreach ($i in $items) {
dism /online /norestart /add-package:$i.FullName
}
dism /online /enable-feature /featurename:Containers-DisposableClientVM /LimitAccess /ALL

最終的に有効化するのが Containers-DisposableClientVM なら add-package するのは Containers を含む全てではなく Containers-DisposableClientVM を含むものだけでも良さそうに見えますが 他も必要になるのでしょうか

> dir C:\Windows\servicing\Packages\*Containers-DisposableClientVM*.mum | select name

Name
----
Containers-DisposableClientVM-merged-Package~31bf3856ad364e35~amd64~en-US~10.0.19041.1.mum
Containers-DisposableClientVM-merged-Package~31bf3856ad364e35~amd64~ja-JP~10.0.19041.1.mum
Containers-DisposableClientVM-merged-Package~31bf3856ad364e35~amd64~~10.0.19041.3636.mum
Containers-DisposableClientVM-Package~31bf3856ad364e35~amd64~en-US~10.0.19041.3636.mum
Containers-DisposableClientVM-Package~31bf3856ad364e35~amd64~ja-JP~10.0.19041.3636.mum
Containers-DisposableClientVM-Package~31bf3856ad364e35~amd64~~10.0.19041.3693.mum
Containers-DisposableClientVM-Package~31bf3856ad364e35~amd64~~10.0.19041.3803.mum
py ランチャーでバージョン一覧表示
py -0

-0 数字の 0
-0p にすると場所が表示されます

Windows で Python を入れるとついてくる py ランチャー
複数の場所やインストール方法で入れた Python を起動できるので便利です

しばらく使ってなかった環境で どのバージョンが入ってるのか一覧を見ようとしたのですが ヘルプにはそれらしい機能がありません
ランチャーなら見れそうなのに

ぐぐってみると普通にコマンドがあるようです
しかし 認識されないコマンドのようでエラーでした
原因は単純にバージョンが古かったみたいです

Python を新しく入れても py ランチャーは更新されないみたいです
カスタムインストールにしても py ランチャーの項目は灰色になってインストールできなくなってました
管理者権限が必要みたいなことが書いてるので管理者権限でインストーラーを起動してみましたが同じでした
一旦手動でアンインストールが必要みたいです

アンインストール後に再度 Python をインストールすると 最新の py ランチャーが入りました
ヘルプに -0 が出ていますし -0 でインストール済みバージョンの一覧が見れます
Windows で拡張子なしのファイルを規定のプログラムで開く
https://superuser.com/questions/13653/how-to-set-the-default-program-for-opening-files-without-an-extension-in-windows

メモ帳で開く場合
管理者権限コマンドプロンプトで以下コマンドを実行

assoc .="No_Extension"
ftype "No_Extension"="C:\Windows\System32\notepad.exe" "%1"

notepad.exe のパスのところを好きなエディタに変える
サクラエディタなら

C:\Program Files (x86)\sakura\sakura.exe

拡張子なしは基本的に設定ファイルなどテキストファイル
とりあえずテキストエディタで問題ないはず



assoc コマンドは拡張子とファイルタイプを関連付けるもの
拡張子に対して 適当に名前をつけれる
引数無しで assoc コマンドだけを実行すると登録済みの一覧が見れる


.htm=htmlfile
.html=htmlfile
.jpe=jpegfile
.jpeg=jpegfile
.txt=txtfile

ftype コマンドはファイルタイプとそれを開くデフォルトのコマンドを関連付けるもの
assoc でつけた名前に対してコマンドを指定できる
引数無しで ftype コマンドだけを実行すると登録済みの一覧が見れる


htmlfile="C:\Program Files\Internet Explorer\iexplore.exe" %1
txtfile=%SystemRoot%\system32\NOTEPAD.EXE %1

ただ .html は Chrome で .txt はサクラエディタになってる PC でも↑
ファイルのプロパティから関連付けたものはここに反映されなくて そっちが優先されるようになってるみたい
拡張子なしの場合はプロパティで設定できないのでこれで設定するしかないみたい

基本的にファイルを右クリックすれば◯◯で開くがメニューにあるのでわざわざ設定する必要性は薄いけど zip の中のファイルとなると右クリックメニューで◯◯を開くを選べないのでそういうときに便利
Windows の VBScript のサポートが終わるらしい
自分には関係ないかなと思ってましたが そういえば使ってるところがありました
ちょっとしたツールでダイアログで入力するために使ってました

bat ファイルはこんな感じで書いておきます

wscript xxx.vbs

xxx.vbs の方はこういう感じです

Dim shell, txt
txt = InputBox("テキスト")

IF Len(Trim(txt)) Then
Set shell = WScript.CreateObject("WScript.Shell")
shell.Run "cmd.exe /c some-command --option " & txt & " & pause"
End If

これで入力用ダイアログが出て ユーザーの入力を受け取ってコマンドに埋め込めます
地味に便利なんですよね
コマンドラインを使えない人向けにもできますし

ただ VBScript が将来的に消えるなら PowerShell に置き換えたほうがいいのかもしれません
たぶんこんなので同じ動きになりそう

bat ファイル

powershell -NoProfile -ExecutionPolicy Unrestricted xxx.ps1

xxx.ps1

Add-Type -AssemblyName "Microsoft.VisualBasic"

$txt = [Microsoft.VisualBasic.Interaction]::InputBox("テキスト")
if ($txt.trim().length) {
some-command --option $txt
pause
}

VBScript より読みやすいしこっちでいいかな
Windows ってファイルを開いてると消せないと思ってたけど
Windows だとファイルを開いたままにしてると そのファイルを消せないと思ってた
なにかのプロセスで開いたままになってて消せなくて そのプロセスを見つけて停止することってよくあるし

でも普通に消せるみたい
Node.js で stream で書き込み中にエクスプローラーからファイルを消してみる

const stream = require("fs").createWriteStream("foo.txt")

stream.on("error", err => console.log({ err }))

setInterval(() => {
stream.write(
Date.now() + "\n",
(err, result) => console.log({ err, result })
)
}, 1000)

↑で毎秒書き込むので適当なところでファイルを消す
例のエラーはなく 普通に消せる

消したあとに ファイルを開いたプロセスが書きこむとどうなるか気になったけど 何も起きないみたい
書き込みは成功扱いで特にエラーは起きない
書き込み時に新規にファイルが作られるわけではなく どこにも出力されない
Linux での扱いと同じみたい

ということは消せないエラーが出てくるものはわざわざ追加でロックするような処理をしてる?
言語によってはデフォルトの挙動がそうなってるのかも

Windows だと OS やファイルシステムの都合で開いてるファイルは消せないものだと思ってたけど できるんだったらこの動きをデフォルトにしてほしい
どこかで開いてるからってエラー出されても面倒なだけで このエラーを見るたび Linux のほうがこういうところは便利だな―と思ってるくらいなので
ローカルに開発環境がない状態でサーバサイド処理を動かしたい
サーバサイドありのウェブアプリケーションを動かして少し修正したいのだけど 開発関係のツールは一切入ってない環境
ブラウザだけならデフォルトの Edge だけで動かせるけどサーバサイドは無理
その PC へ Node.js や PHP 等を入れたいけど 追加インストールや exe を持ってきての実行は不可
WSL や Sandbox があればそこにインストールできるけど これらも入ってない
何かいい方法はないものかな

ブラウザ上で Linux が動かせる WebVM というのがあって Python は動いたけどブラウザ上という制限があるからネット接続系機能は使えない
パッケージインストールも自分のローカルのファイルのダウンロードもできない

ローカルでやることを諦めてリモートデスクトップや ssh を使おうにも接続先がない
開発環境として使える PC は外部からアクセスできるようにしてない
VPN でネットワークに入れても 直接使ってないときはシャットダウンしてる

AWS や GCP を使ってクラウドに頼ることはできるけど有料になる
お金払うほどじゃない
新規アカウントを作れば無料分がありそうだけど このためにわざわざアカウントを作るのは避けたい

この状況だと無理そうかな

Windows にスナップショットを取って完全にその状態に戻せる機能があればいいけど システムの復元機能は OS アップデート時のシステムフォルダだけだと思うし たぶんなさそう
Windows 自体を書き換えて元に戻すよりは最初から一時環境を操作して破棄できた方がいいから Sandbox のほうが向いてる
だけど Sandbox は追加インストールが必要だし Pro エディション以上限定
なにかのソフトを使いたいけどインストールできないしたくない環境でも Windows 本体部分には影響無しでインストールして試せるし セキュリティ的にも有用なんだから全部の Windows で標準で使える機能にしていいと思うんだけど
WSL2 のファイルを Windows で開くと読み取り専用になる
WSL2 のファイルを Windows から扱う場合

\\wsl$\Ubuntu\tmp

のようなアドレスをエクスプローラで開けばいいです
これだと Ubuntu ディストリビューションの /tmp フォルダを開けます
後は Windows 上のファイルを扱うようにエディタで開いたりエクスプローラの操作でフォルダ移動したりできます

普段はこれで問題なかったのですが なぜかファイルが読み取り専用になって編集できませんでした
編集できるファイルをもあってその違いを調べると Linux 側のファイルの所有者情報が原因のようでした

Windows からのアクセスは WSL インスタンスの初回起動時に作るユーザの権限になっているようです
root で作られたファイルは Windows から変更できません
root 権限だと /etc とか /usr とかそういうところになってくるので 誤ってエクスプローラでドラッグアンドドロップして移動してしまったりで Linux 側が動作しなくなることを避けるためでしょうか

touch a
sudo touch b



-rw-r--r--  1 user user    0 Mar  5 23:40 a
-rw-r--r-- 1 root root 0 Mar 5 23:40 b

となっていると Windows で
    a は書き込みできる
    b は読み取り専用
となります

sudo chown user:user b

で b の所有者とグループを a と同じにすると b も書き込みできるようになります

普段は Windows 側で書き込むところを root 権限にしないので問題はなかったのですが Docker を使ってコンテナ内で作業している部分でファイルの編集は Windows でやるとしたときに困りました
コンテナ内では root 権限なので 作るフォルダやファイルがすべて Windows では読み取り専用になってしまいます
コンテナにマウントしたときはホストの user というユーザは認識されてないみたいで ユーザ id の 1000 になってました
「sudo chown 1000:1000 file」 で書き込みできるようになりましたが 毎回は面倒です

WSL2 のローカルに実体を置いて Docker コンテナと Windows から参照するというのがあまり良くないのかもしれません
WSL2 と Docker コンテナからの読み書きが多少遅くなってもいいなら Windows 側に実体をおいたほうがこういう権限問題は起きずに済んで良いのかもしれません
Windows のプロダクトキー取得
よく見る方法
コマンドプロンプトでこのコマンドを入力

wmic path SoftwareLicensingService get OA3xOriginalProductKey

時々これで取得できない環境がある

他の方法を探すと PowerShell で遠回しに↑と同じ処理を実行してるものだったり
レジストリを参照してるけどプロダクトキーじゃなくてプロダクト ID の取得方法が書かれていたり
ID は桁数が違うからみればわかるはず

使える方法だとソフトのインストールが必要になったりであまりやりたくない方法
スクリプトを探すとこういうのがあったけど VBS
https://gist.github.com/craigtp/dda7d0fce891a087a962d29be960f1da

実行するだけなら VBS で困らない気はするけど気持ち的にイヤなのと読みづらいのでなにしてるかわかりづらいのがなんかイヤだったので PowerShell のスクリプトにした

$dpid = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion").DigitalProductId
$is_win8 = [Math]::Truncate($dpid[66] / 6) -band 1
$dpid[66] = ($dpid[66] -band 0xF7) -bor (($is_win8 -band 2) * 4)

$keyoffset = 52
$maps = "BCDFGHJKMPQRTVWXY2346789"
$key = ""
$last = 0

for ($i = 24; $i -ge 0; $i--) {
$current = 0
for ($j = 14; $j -ge 0; $j--) {
$current = $current * 256
$index = $j + $keyoffset
$current = $dpid[$index] + $current
$dpid[$index] = [Math]::Truncate($current / 24)
$current = $current % 24
}
$key = $maps[$current] + $key
$last = $current
}

$key = $key.Substring(1).Insert($last, "N")
$key = ($key -split "(.{5})" | ? { $_ }) -join "-"
echo $key

wmic コマンドでキーを取得できる環境でこのスクリプトを動かして同じ結果になることを確認したのでたぶん大丈夫なはず
wmic コマンドで取得できない環境でこの方法で取得できるかは未確認
C ドライブ全体のフォルダ共有
デフォルトで C ドライブなどドライブルートはフォルダ共有されています

\\172.23.116.130\c$\

みたいに共有名にドライブレターと $ を入れます
隠されているのでコンピュータ名だけを指定して共有一覧を見ても表示されていません

PowerShell の Get-SmbShare コマンドで共有リストを取得するとちゃんと含まれています

PS C:\Users\nexpr> Get-SmbShare

Name ScopeName Path Description
---- --------- ---- -----------
ADMIN$ * C:\WINDOWS Remote Admin
C$ * C:\ Default share
IPC$ * Remote IPC

C$ へのアクセスで使うユーザ情報は Administrator の必要があります
普段使いの管理者権限ユーザの情報ではログインできません

Administrator は無効になってることが多いので 使う場合は

コンピュータの管理 > ローカル ユーザとグループ > ユーザー

から Administrator を選んで

◯ プロパティを開いてアカウントを無効にするのチェックをはずす
◯ 右クリックからパスワードの設定

が必要です

設定すると Administrator と設定したパスワードで C$ を開けます

セキュリティ的にはあまり良くないと思いますが VM やサンドボックスのファイルすべてをホスト側のエクスプローラで操作したいときに使えます
Windows Sandbox が起動できない
久々に起動しようとしたら

Windows サンドボックスを開始できませんでした。

Error 0xc0370400 vSMB 保存状態のデータから読み取られたファイルが見つからなかったため、この仮想マシンを復元できません。
保存状態のデータを削除してから、仮想マシンを起動してください。

というエラーで起動できない
ググるとこんなページがあって サンドボックス機能を無効にしてから再起動してまた有効にすればいいみたいだけどかなり面倒

https://answers.microsoft.com/en-us/windows/forum/all/windows-sandbox/dc54884d-ba8d-4be1-8245-cf255af1ea9f
Chrome をアクティブにすると CPU 使用率が上がる
少し重めの処理を実行中にタスクマネージャを見ると
CPU の使用率が 40% 前後 速度が 1.89 GHz 固定

この状態で Chrome のウィンドウをクリックしてアクティブにすると
CPU の使用率が 60% ちょっと 速度が 3.22 GHz 前後
まで上がる

少し重めの処理は Chrome とは関係ないプログラムだし Chrome では特に重い処理はしてない
実際にタスクマネージャでの使用率はほぼ 0%
一番使用率が高いのは少し重めの処理のプロセス
なんで関係ない Chrome のウィンドウをアクティブにするかどうかで変わるんだろう?
Chrome 以外に少し重めの処理をしてるプログラムのウィンドウやエクスプローラやタスクマネージャなどをアクティブにしても変化はなかった
今のところは Chrome だけ

Chrome 以外をアクティブにすると CPU 使用率は下がって また Chrome をアクティブにすると上がる
パーティションルートはシステムフォルダ属性ついてる
「C:\userfiles」 フォルダをバックアップしようと robocopy で 「G:\backups\userfiles」 にコピーしたときのこと
コピー中はコピー先に userfiles フォルダがあって途中経過も見えていました
長時間かかる量だったのでしばらく待って完了してから見てみました
すると……
userfiles フォルダがありません
ログではエラーはなく正常終了しています
消した覚えはないけど一応ゴミ箱を見てみるも見つかりません

またコピーし直しかぁと思いつつ なんとなくフォルダのプロパティを見てみると
データがあるようなサイズです
Windows バグったのかなと再起動しようとしたとき もしかして と思ってシステムフォルダを表示するようにしてみると……
userfiles フォルダが出てきました

「C:\userfiles」 は少し特殊でパーティションのルートです
基本は D: や E: などのドライブレターを割り当てますが Linux 風にフォルダにマウントしています
内部的にはボリュームへのジャンクションみたいです
この場合は普通にエクスプローラで見えているのでシステムフォルダとは思いもしませんでした
しかし attrib で見てみると SH 属性 (システムフォルダと隠しフォルダ) を持っていました

C:\>attrib userfiles
SH C:\userfiles

なので robocopy で属性も含めてコピーしていると 「G:\backups\userfiles」 もシステムフォルダと隠しフォルダ属性を持ちます
こっちは普通のフォルダなので属性の効果で見えなくなっていたようです
途中まで見えていたのは robocopy が属性をセットするのがフォルダの中身のコピーを終えてからだからのようです
「G:\backups\usefiles」 はシステムフォルダの必要がないので属性を削除します

attrib -S -H userfiles

これで無事完了
robocopy でコピーするときにルートフォルダのみ A 属性外せないのかな
yarn create が Windows だとエラーになる
yarn create を使ってみたらエラーが発生
ドキュメントにある例の "yarn create react-app my-app" コマンドで起きることを確認

エラーは 'C:\Program' が見つからないとかそういう感じのやつ
エラーメッセージを見る限りは単純にパスのクオート漏れ
yarn が内部で実行するコマンドで Node.js のパスを指定する部分で起きてる
Node.js の exe が Program Files 以下にあると使えないぽい

ソースを軽く見た感じだと exec じゃなくて spawn を使ってるし自動でクオートされてそうなんだけど
一応バージョンを最新まで上げてみたけど変わらなかった

Windows だと標準インストーラでも Nodist でも Program Files 以下になるからほとんどの人が動かない気がするのに結構前からこの状態
Windows で yarn create 使うような人がそもそも少ないのかも

仕方ないので 私は npm init で代替



[追記]

原因は spawn のオプションに shell: true を使ってるからだった
そのままコマンドプロンプトに打ち込む形になって command 変数にスペースがあるとエラーになる
shell: false にするとスペースがあっても大丈夫だけど 実行するのが .cmd ファイルなので shell: false だと動かない

shell: true のまま動かすために command 変数を "" でクオートする処理を追加する
修正するファイルは node_modules\yarn\lib\cli.js
babel+webpack の変換で大きく変わっているので 「child.spawn(command」 で検索しても見つからない
「.spawn(command, rest,」 で検索すると見つかるはず
その行の直前に↓のコードを追加

command = `"${command}"`

これで動くはず

ただ yarn create は create-react-app などのパッケージをグローバルインストールするようなので 失敗直後に create-react-app コマンドは使えるようになってる
わざわざ修正するよりも create-react-app などのコマンドを打つ方が早い
win10 のファイルダイアログが変わった
win10 を 1909 にしてからファイルやフォルダを開いたり保存したりするダイアログが微妙に変わった気がする
アドレスバーが縦に広かったり色も微妙に違うような気がする
気になったのが最近だから 1909 からのはず たぶん