Showing Posts From
PowerShell
Windows 开机自启:脚本、EXE、Python 服务的四种做法
Windows 上"开机自启"根据程序性质要选不同方式。一股脑塞启动文件夹经常出问题——GUI 程序有个 UAC 弹窗、脚本要读用户目录、长驻服务要跑在 SYSTEM 下——分类拆开来看。 方式一:启动文件夹(普通程序) Win + R 打开: shell:startup这是当前用户的启动目录。把 .exe 或 .lnk 快捷方式扔进去就行。全用户共用: shell:common startup局限:用户登录后才启动 弹 UAC 会需要手动点 关了窗口就没了适合:桌面小工具、常用软件(VSCode、Chrome 等已经自带这个)。 方式二:NSSM 把脚本包成服务(推荐) 长驻的 Python、Node、FastAPI、Uvicorn 等脚本,最省心是用 NSSM。它能把任何 exe/bat/脚本包装成 Windows 服务。 管理员 CMD: nssm install MyService弹出 GUI,填三项: Application → Path: C:\Python311\python.exe Application → Arguments: -m uvicorn main:app --host 0.0.0.0 --port 8000 Application → Startup directory: D:\project设自动启动: sc config MyService start= auto(start= 和 auto 之间必须有空格。) 启动 / 停止 / 删除: net start MyService net stop MyService nssm remove MyService confirmNSSM 的好处:崩溃自动重启(Details 里配 Exit Action) stdout / stderr 可以重定向到日志文件 支持环境变量、依赖、恢复策略 卸载干净方式三:原生 sc create(真 EXE 程序) 已经写成了 Windows Service 兼容的 EXE: sc create MyService binPath= "D:\app\server.exe" start= auto sc start MyService sc delete MyService局限:只能接已经实现了 ServiceMain 的 EXE 普通脚本用这个会秒退,要靠 NSSM方式四:任务计划程序(脚本 / GUI / 用户上下文) 需要在用户登录后启动、或者要 GUI、或者 SYSTEM 下跑不了的: schtasks /create /tn "MyTask" ^ /tr "C:\Users\me\bin\worker.py" ^ /sc onlogon场景:只登录时启动:/sc onlogon 每次开机(不管登录):/sc onstart(需要管理员) 每天 03:00:/sc daily /st 03:00管理: schtasks /query /tn "MyTask" schtasks /run /tn "MyTask" schtasks /delete /tn "MyTask" /f选哪一种场景 推荐只想开机跑一次的桌面程序 启动文件夹Python/Node 长驻脚本、API、爬虫 NSSM(默认选它)已经是 Windows Service 兼容 EXE sc createGUI 程序、要用户桌面 session 任务计划 onlogon系统级、无用户登录也要跑 任务计划 onstart 或 NSSM一句话总结 长驻脚本 = NSSM,开机自动、崩溃自愈、日志齐全。其它类型再按上面表格分。
PowerShell 设置环境变量:临时、当前用户、系统级
PowerShell 里改环境变量有三档:当前会话、当前用户永久、系统级永久,权限和作用范围各不相同。搞混了一堆脚本会失效。 临时(仅当前 PowerShell 窗口) $env:MY_TOKEN = "secret" echo $env:MY_TOKEN只影响当前会话 关掉窗口就没了 90% 的临时脚本调试用这个就够对子进程也生效: $env:PYTHONPATH = "D:\repo\src" python main.py # main.py 里能读到永久(当前用户) [System.Environment]::SetEnvironmentVariable("MY_TOKEN", "secret", "User")写到注册表 HKCU\Environment 新开的进程能读到 当前 PowerShell 窗口需要重开 才能通过 $env:MY_TOKEN 看到不重开也想立刻用的话: $env:MY_TOKEN = "secret" # 先本地设一份永久(系统级) 需要管理员 PowerShell: [System.Environment]::SetEnvironmentVariable("MY_TOKEN", "secret", "Machine")写到 HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment 所有用户都能读到 用于系统服务、多用户共享配置读取和删除 读: $env:MY_TOKEN [System.Environment]::GetEnvironmentVariable("MY_TOKEN", "User") [System.Environment]::GetEnvironmentVariable("MY_TOKEN", "Machine")删(把值设为空字符串就是删除): [System.Environment]::SetEnvironmentVariable("MY_TOKEN", $null, "User")追加到 PATH 写 PATH 一定要先读旧的再拼,不然会把系统原本的 PATH 覆盖掉: $old = [System.Environment]::GetEnvironmentVariable("Path", "User") $new = "$old;C:\Users\me\bin" [System.Environment]::SetEnvironmentVariable("Path", $new, "User")去重和验证: $new.Split(";") | Sort-Object -Unique三档对比目标 写法 生效范围只当前窗口 $env:X = "v" 当前会话 + 子进程当前用户永久 [Environment]::SetEnvironmentVariable("X","v","User") 新开进程,用户级系统级永久(管理员) [Environment]::SetEnvironmentVariable("X","v","Machine") 新开进程,所有用户老 Windows API:setx 老一辈 Windows 用 setx: setx MY_TOKEN secret # 用户 setx MY_TOKEN secret /M # 系统(管理员)坑:有 1024 字符限制,PATH 老长了会被截断 也不影响当前窗口一般还是推荐 [Environment]::SetEnvironmentVariable。 一句话总结 会话内 $env:X;永久用 [Environment]::SetEnvironmentVariable,第三参数 "User" 或 "Machine" 决定作用域。改 PATH 记得先读再拼。
Windows 追加目录到 PATH:CMD 和 PowerShell 的正确姿势
Windows 上装完 Maven / Java / Python,最常做的一件事就是把 bin 目录塞进 PATH。老一辈教程都写 setx PATH "%PATH%;...",看着能跑,实际有个特别坑的边界。 CMD 方式:setx 追加到当前用户 PATH: setx PATH "%PATH%;D:\soft\apache-maven-3.9.15\bin"追加到系统 PATH(需要管理员 CMD): setx /M PATH "%PATH%;D:\soft\apache-maven-3.9.15\bin"新开的 CMD 才能读到。当前窗口立即用: set PATH=%PATH%;D:\soft\apache-maven-3.9.15\bin mvn -vsetx 的两个坑 1. 会展开 %PATH%,把用户和系统 PATH 混起来 %PATH% 在 CMD 里是 系统 + 用户 PATH 的合并结果。你 setx PATH "%PATH%;X" 会把两份合起来写到用户 PATH 里,重复且混乱。 2. 1024 字符截断 setx 有个硬伤:值超过 1024 字符会静默截断。老系统 PATH 已经很长,一次 setx 直接把后半段吞掉。 PowerShell 方式(推荐) [Environment]::SetEnvironmentVariable 更精确——读用户就读用户、写用户就写用户,也没 1024 字符限制。 追加到当前用户 PATH: $addPath = "D:\soft\apache-maven-3.9.15\bin" $current = [Environment]::GetEnvironmentVariable("Path", "User")if ($current -notlike "*$addPath*") { [Environment]::SetEnvironmentVariable("Path", "$current;$addPath", "User") Write-Host "已追加:$addPath" } else { Write-Host "PATH 已存在该目录" }-notlike "*X*" 防止重复添加 "User" 参数明确只改用户 PATH,不动系统 PATH追加到系统 PATH(管理员 PowerShell): $addPath = "D:\soft\apache-maven-3.9.15\bin" $current = [Environment]::GetEnvironmentVariable("Path", "Machine") if ($current -notlike "*$addPath*") { [Environment]::SetEnvironmentVariable("Path", "$current;$addPath", "Machine") }当前会话立刻生效: $env:Path += ";D:\soft\apache-maven-3.9.15\bin" mvn -v通用检查 # 看用户 PATH [Environment]::GetEnvironmentVariable("Path", "User") -split ";"# 看系统 PATH [Environment]::GetEnvironmentVariable("Path", "Machine") -split ";"# 看合并后的 PATH $env:Path -split ";"去重: $env:Path -split ";" | Where-Object { $_ } | Sort-Object -Unique移除某条 用户 PATH 里删掉某条: $remove = "D:\soft\apache-maven-3.9.15\bin" $paths = ([Environment]::GetEnvironmentVariable("Path","User") -split ";") | Where-Object { $_ -ne $remove -and $_ } [Environment]::SetEnvironmentVariable("Path", ($paths -join ";"), "User")一句话总结CMD 只是想加一条:setx PATH "%PATH%;X",小心 1024 截断 认真加:管理员 PowerShell + [Environment]::SetEnvironmentVariable 显式指定 User/Machine 加完记得新开终端才能读到;当前窗口用 $env:Path += ";X"
