<# .SYNOPSIS Add the bundled node-runtime directory to the per-user PATH, if it is not there already. .DESCRIPTION build/installer.nsh's customInstall does this at install time for the NSIS Full target (HKCU\Environment, no elevation -- a per-user registry write needs none). An AppX/MSIX install has no install-time hook at all, elevated or not -- not a signing/elevation gap like the firewall rule or service-mode, but the more basic fact that MSIX runs no custom code whatsoever during setup. So the MSIX target calls this itself, once, on first launch (main.js's winEnsureNodeOnPath()) instead. Idempotent and safe to run on every launch of any packaged Windows build, NSIS Full included: if the installer already added the entry, this is a fast no-op query. Never touches PATH for a Light install (no bundled node-runtime to add) -- the caller only invokes this when hasBundledNode() is true. Broadcasts WM_SETTINGCHANGE afterward so already-open shells notice -- same as the installer's own SendMessage call. New shells pick it up either way. .PARAMETER NodeDir Full path to the node-runtime directory to add. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)][string]$NodeDir ) $ErrorActionPreference = "Stop" $key = "Registry::HKEY_CURRENT_USER\Environment" $current = (Get-ItemProperty -Path $key -Name "Path" -ErrorAction SilentlyContinue).Path if ($null -eq $current) { $current = "" } $parts = $current -split ";" | Where-Object { $_ -ne "" } $already = $parts | Where-Object { $_.TrimEnd('\') -ieq $NodeDir.TrimEnd('\') } if ($already) { Write-Output "already present" exit 0 } $next = if ($parts.Count -gt 0) { ($parts + $NodeDir) -join ";" } else { $NodeDir } # ExpandString, not String -- matches installer.nsh's WriteRegExpandStr, so any # %VAR% another entry already carries on this machine keeps expanding. New-ItemProperty -Path $key -Name "Path" -Value $next -PropertyType ExpandString -Force | Out-Null Add-Type -Namespace MeshBay -Name NativeMethods -MemberDefinition @" [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)] public static extern System.IntPtr SendMessageTimeout(System.IntPtr hWnd, uint Msg, System.UIntPtr wParam, string lParam, uint fuFlags, uint uTimeout, out System.UIntPtr lpdwResult); "@ $HWND_BROADCAST = [IntPtr]0xffff $WM_SETTINGCHANGE = 0x1a $result = [UIntPtr]::Zero [MeshBay.NativeMethods]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE, [UIntPtr]::Zero, "Environment", 2, 5000, [ref]$result) | Out-Null Write-Output "added"