متغیرهای محیطی در ویندوز؛ Machine، User و Process
فهم سه سطح متغیر محیطی در ویندوز، مشاهده و تغییر با GUI و PowerShell، ارثبری به فرایند فرزند و اشتباههای رایج توسعهدهنده.
بنیانگذار و مهندس محصول

وقتی میگویید NODE_ENV را گذاشتم ولی اپ نمیبیند، یا کلید API در یک ترمینال هست و در دیگری نیست، معمولاً قربانی سطح اشتباه متغیر محیطی شدهاید. ویندوز برخلاف یک export ساده در شِل لینوکس، سه دامنهٔ رایج دارد: Machine (سیستم)، User (کاربر) و Process (نشست جاری).
این مقاله مدل را توضیح میدهد، روش مشاهده و تغییر امن را نشان میدهد، و مرز با فایل .env اپلیکیشن را روشن میکند. PATH بهخاطر اهمیت جدا در ۱۸۸ آمده، ولی قوانین سطحها همان است.

پاسخ کوتاه
متغیرهای محیطی زوج نام/مقدار رشتهایاند که فرایند به فرزندانش ارث میدهد. در ویندوز مقدار مؤثر یک نشست از ترکیب Machine و User ساخته میشود و در Process قابل تغییر موقت است. تغییر $Env:NAME فقط همان نشست را عوض میکند مگر با API سطح User/Machine پایدارش کنید. برای دیدن تفاوت سطوح از System.Environment استفاده کنید نه فقط چاپ $Env.
اگر ترمینال را نبستی، شاید تغییر پایدار را هرگز نبینی — و اگر فقط $Env را عوض کردی، شاید هیچوقت پایدار نبوده باشد.
سه سطح را دقیق ببینید
| سطح | دامنه | نیاز مجوز | مثال کاربرد |
|---|---|---|---|
| Process | همین شِل/فرایند | خیر | تست موقت، CI step |
| User | کاربر واردشده | خود کاربر | PATH شخصی، توکن توسعه |
| Machine | همهٔ کاربران | Administrator | ابزارهای سیستمwide |
طبق مستند about_Environment_Variables در Microsoft Learn، فهرست Process از روی Machine و User هنگام ساخت فرایند به ارث میرسد و بعداً میتواند در همان فرایند تغییر کند بدون اینکه لزوماً به رجیستری برگردد.
مشاهده در PowerShell
powershell
Get-ChildItem Env: | Sort-Object Name | Select-Object -First 20 $Env:USERNAME $Env:TEMP
powershell
[System.Environment]::GetEnvironmentVariable('PATH','Process') [System.Environment]::GetEnvironmentVariable('PATH','User') [System.Environment]::GetEnvironmentVariable('PATH','Machine')
این سه خط آخر عادت طلایی دیباگ env هستند. خیلیها فقط Process را میبینند و فکر میکنند User خراب است.
تغییر موقت در برابر پایدار
موقت (Process)
powershell
$Env:NODE_ENV = 'development' $Env:MY_TOKEN = 'dev-only'
برای فرزندانی که از همین شِل شروع میشوند دیده میشود. بستن پنجره یعنی پایان.
پایدار User یا Machine
powershell
[System.Environment]::SetEnvironmentVariable('NODE_ENV','development','User') # Machine نیاز به ارتفاع و احتیاط: # [System.Environment]::SetEnvironmentVariable('NAME','VALUE','Machine')
بعد از تغییر پایدار، پنجرههای از قبل باز معمولاً مقدار قدیم Process را نگه میدارند. یک Terminal جدید باز کنید. ابزار setx هم وجود دارد ولی دامهای نقلقول و طول دارد؛ برای اسکریپت مدرن، API بالا معمولاً شفافتر است.
GUI ویندوز
Settings → System → About → Advanced system settings → Environment Variables همان تفکیک User و System را نشان میدهد. برای آموزش مبتدی عالی است؛ برای تکرارپذیری و مستندسازی تیم، اسکریپت PowerShell را ترجیح دهید تا مشخص باشد چه چیزی در کجا نوشته شده.
ارثبری و فرزندان
وقتی از VS Code یا Visual Studio ترمینال باز میکنید، env از والد IDE ارث میگیرد. اگر IDE قبل از تغییر PATH باز شده، ترمینال داخلش ممکن است مقدار کهنه داشته باشد. همین دلیل است که گاهی where.exe در یک پنجره پیدا میکند و در دیگری نه.
سرویسهای ویندوز معمولاً env جداگانهای دارند و الزاماً همان User شما را نمیبینند. فرض نکنید چون در PowerShell تعاملی متغیر هست، سرویس هم آن را دارد.
رابطه با فایل .env اپ
فایل .env داخل ریپو قرارداد اپ است نه سیستمعامل. فریمورک هنگام شروع آن را میخواند. قاطی کردن رازها بین .env، User env و CI secrets بدون سیاست مشخص، هم دیباگ را سخت میکند هم نشت را آسان. قاعدهٔ ساده:
- راز ماشین توسعهٔ شخصی: User env یا secret manager محلی — نه commit.
- پیکربندی پروژه: .env.example بدون راز + .env محلی gitignore.
- CI: secrets پایپلاین، نه PATH سیستم Agent.
نامهای حساس و برخوردها
بعضی نامها برای سیستم معنی دارند: PATH، PATHEXT، TEMP، APPDATA، USERPROFILE. آنها را حذف یا خرد نکنید. در لینوکس نامها حساس به حروفاند؛ در ویندوز معمولاً حساسیت حروف برای env کمتر دردسرساز است ولی در کد چندسکویی فرض یکسان نکنید.
اشتباههای رایج
- تغییر Process و انتظار ماندگاری بعد از ریبوت.
- نوشتن به Machine برای کاری که User کافی بود.
- باز نگهداشتن Terminal کهنه و فکر کردن که set پایدار اعمال نشده.
- گذاشتن Secret در Machine تا همهٔ کاربران ماشین ببینند.
- استفاده از setx PATH بدون فهم اینکه ممکن است مقدار را کوتاه یا خراب کند.
چکلیست دیباگ وقتی اپ متغیر را نمیبیند
- در همان ترمینالی که اپ را start میکنید $Env:NAME را چاپ کنید.
- سطح User و Machine را جدا بخوانید.
- IDE/Terminal را یکبار کامل ببندید و باز کنید.
- اگر سرویس است، محیط سرویس را جدا بررسی کنید.
- مطمئن شوید خود اپ نام را درست و با حروف مورد انتظار میخواند.
سوالات متداول
آیا متغیرها فقط برای PATH مهماند؟
خیر. زبان برنامهنویسی، پروکسی، جاوا_HOME، کلیدهای SDK و دهها تنظیم دیگر از همین مکانیزم میآیند.
در cmd چطور ببینم؟
فرمان set و set NAME=value برای Process. برای پایدار معمولاً UI یا setx/API.
برای تیم چه استانداردی بگذاریم؟
حداقل: مستند کنید کدام متغیر User است، کدام در .env، کدام در CI. ابهام گرانتر از تکرار است.
اگر راهحل شما تغییر سطح Machine بود، بگویید چرا User کافی نبود. اگر Force کردید، بگویید چرا توقف ملایم شکست. این انضباط کوچک کیفیت عملیاتی تیم را بالا میبرد.
قبل از اینکه مشکل را بستهشده اعلام کنید: نشست جدید را تست کنید، مسیر یا پورت یا سرویس را دوباره با ابزار ساختیافته تأیید کنید، و یک خط در یادداشت تیمی بنویسید که علت ریشهای چه بود. بدون این سه قدم، همان تیکت هفتهٔ بعد برمیگردد.
چکلیست پایانی قبل از بستن تیکت
برای تست، یک متغیر مشخص مثل MYAPP_DEBUG را فقط در Process ست کنید تا مطمئن شوید اپ همان نشست را میخواند؛ بعداً به User ارتقا دهید اگر لازم شد.
خیلی از IDEها env را از launch configuration میخوانند نه فقط از سیستم. اگر در Terminal مقدار درست است ولی در Run/Debug نیست، فایل launch.json یا تنظیمات پروژه را ببینید. سه منبع جدا یعنی سه جا برای اشتباه.
هماهنگی با IDE و دیباگر
تاریخچهٔ PowerShell میتواند مقادیری که تایپ کردهاید را نگه دارد. روی ماشین اشتراکی، از وارد کردن Secret بهصورت خام در خط فرمان خودداری کنید.
گذاشتن توکن در متغیر محیطی Process راحت است ولی در فهرست فرآیندها، گزارش کرش، و گاهی ابزار مانیتور لو میرود. برای رازهای واقعی از Secret Store سیستم، vault، یا حداقل فایل خارج git با ACL محدود استفاده کنید. مقالهٔ عمومی Secrets را با مدل ویندوز ترکیب کنید.
رازها و تاریخچه
در محیط شرکتی، بعضی متغیرها را سیاست دامنه مینویسد و تغییر User ممکن است در ورود بعدی برگردد. قبل از جنگ با مقدار، منبع نوشتن را پیدا کنید: نصبکننده، اسکریپت login، یا Policy.
TEMP و TMP، USERPROFILE، SystemRoot، windir و ComSpec از پایههای اجرا هستند. پاک کردن یا تغییر نادرست آنها خطاهای عجیب در نصبکننده و کامپایلر میسازد. اگر آزمایش میکنید، فقط در سطح Process و برای همان نشست باشد.
متغیرهای سیستمی که نباید بیگارد لمس شوند
نسخهبندی اسکریپتهای عیبیابی را جدی بگیرید. یک gist شخصی یا پوشه در ریپو داخلی با تاریخ و پیشفرضهای ایمن، بهتر از حافظهٔ شفاهی است.
مستند رسمی را نخواندن و اعتماد به اولین نتیجهٔ جستجو، اجرای همیشگی Elevated، و تغییر Machine برای مشکل User، سه الگوی پرهزینهاند. هزینهٔ واقعیشان معمولاً ساعتها بعد معلوم میشود؛ وقتی محیط برای همکار یا CI میشکند.
اشتباههای سطح بالاتر
در پایان تمرین، همه چیز را به حالت اول برگردانید: فرایند تست را ببندید، متغیر موقت را رها کنید، و سرویس را اگر تغییر دادید به Startup Type قبلی برگردانید. پاکسازی بخشی از حرفهایگری است.
یک سرور محلی بالا بیاورید، پورتش را پیدا کنید، فرایند را بشناسید، یک متغیر محیطی موقت ست کنید، PATH را فقط مشاهده کنید بدون تغییر مخرب، وضعیت یک سرویس بیخطر را بخوانید، و پنج رویداد اخیر Application را ببینید. این مدار بسته، دانش را از حالت خواندنی به حالت عضلانی میبرد.
تمرین پیشنهادی سیدقیقهای
اگر از لینوکس آمدهاید، معادل ذهنی بسازید ولی فرمان را عیناً ترجمه نکنید. مدل سرویس ویندوز با systemd شباهت مفهومی دارد و تفاوت ابزاری. مدل env با export شباهت دارد و تفاوت سطح Machine و User.
مفاهیم این مقاله را با Terminal، PowerShell، فرایند، پورت، env، PATH، سرویس و Event Viewer بهصورت حلقه ببینید نه جزایر جدا. بیشتر تیکتهای واقعی دو یا سه حلقه از این زنجیره را درگیر میکنند.
ارتباط با بقیهٔ سری ویندوز
تفاوت محیط خانگی و لپتاپ سازمانی را دستکم نگیرید. آنتیویروس، پروکسی، و سیاست اجرای اسکریپت رفتار ابزارها را عوض میکنند. اگر فقط روی یک ماشین تست میکنید، نتیجه را حقیقت مطلق ندانید.
هر بار که راهحل موقتی پیدا میکنید، همان را به یک فرمان قابلکپی در یادداشت شخصی تبدیل کنید. هفتهٔ بعد همان فرمان را از حافظه نمینویسید؛ از دفترک میآورید و خطا کمتر میشود.
در کار واقعی، مشکلها ترکیبیاند: پورت اشغال، PATH کهنه، سرویس متوقف، و ترمینال با پروفایل غلط همزمان ظاهر میشوند. بهجای تغییر همزمان همه چیز، یک متغیر را ثابت نگه دارید و فقط یک فرض را آزمایش کنید. این نظم علمی سرعت عیبیابی را بیشتر از هر میانبر افزایش میدهد.
عمق عملی بیشتر برای کار روزانه
تغییرات Machine، سیاست دامنه، و آنتیویروس مرکزی معمولاً خارج از اختیار شماست. آنچه در اختیار شماست: پروفایل Terminal، اسکریپت User، انتخاب پورت پروژه، و خواندن لاگ. روی لایهٔ قابلکنترل تمرکز کنید و برای بقیه تیکت شفاف با شاهد بسازید.
مرز مسئولیت توسعهدهنده و IT
اگر وسط راه مجبور به Force شدید، بعداً علت را پیدا کنید که چرا توقف ملایم کار نکرد: قفل فایل، انتظار شبکه، یا بنبست رشتهها. Force بدون یادگیری، همان مشکل را تکرار میکند.
در هر مرحله یک شاهد بنویسید: خروجی کوتاه فرمان یا Event ID. وقتی از کسی کمک میگیرید، شاهد بهتر از توصیف احساسی است. همین عادت در تیمهای دورکاری ارزش دوچندان دارد.
فرض کنید بعد از ریبوت، API محلی بالا نمیآید. اول وضعیت سرویس وابسته را بخوانید، بعد پورت را با Get-NetTCPConnection چک کنید، بعد PATH و متغیرهای لازم اپ را در همان نشست تأیید کنید، و در نهایت اگر سرویس fail شده Event Viewer را روی زمان بوت فیلتر کنید. این ترتیب از پراکنده کاری جلوگیری میکند.
سناریوی ترکیبی که باید یکبار کامل بروید
خلاصه
در ویندوز بدون تفکیک Machine/User/Process، دیباگ env شانسی میشود. موقت را با $Env، پایدار را با System.Environment، و اعتبار را با باز کردن نشست جدید انجام دهید. PATH را در مقالهٔ بعد عمیقتر ببینید؛ همان مدل سطحهاست با حساسیت بیشتر به ترتیب و آسیب.
منابع و مراجع
- Microsoft Learn — about_Environment_Variables — https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_environment_variables
- Microsoft Learn — Environment.SetEnvironmentVariable — https://learn.microsoft.com/dotnet/api/system.environment.setenvironmentvariable
- Microsoft Learn — Environment.GetEnvironmentVariable — https://learn.microsoft.com/dotnet/api/system.environment.getenvironmentvariable
- Microsoft Learn — set (command) — https://learn.microsoft.com/windows-server/administration/windows-commands/set_1
نویسنده
سهیل ابراهیمپور بنیانگذار FutureForge است. روی طراحی محصول، معماری و استقرار نرمافزار سفارشی کار میکند.
یادداشتهای مرتبط
اگر در انتخاب معماری یا مسیر توسعه مطمئن نیستید، میتوانید درباره پروژه صحبت کنیم.
مسئله و محدودیت را بنویسید. اگر تطابق داشته باشیم، برای گفتگو هماهنگ میکنیم.




