62

I want to have an environment variable that contains the day of week in cmd.exe.

When I run this command I get the result I want.

C:\Users\tisc> powershell (get-date).dayofweek
Friday

Here I'm trying to store the result in an environment variable.

C:\Users\tisc> set dow = powershell (get-date).dayofweek

But when I try to get it I don't get the string as I wanted.

C:\Users\tisc> set dow
DoW=0
dow = powershell (get-date).dayofweek

My goal is to use the variable in a batch file for some backup scripts.

t0r0X
  • 109
  • 1
  • 1
  • 8
Tim
  • 721
  • 1
  • 5
  • 8

7 Answers7

92

You can use something like:

$env:DOW = "foo"
Peter Mortensen
  • 2,319
  • 5
  • 23
  • 24
Ion Todirel
  • 1,044
  • 7
  • 4
23

You should run both commands in PowerShell as PowerShell is more than capable of manipulating environmental variables.

I.e.:

$dow = (get-date).dayofweek
[Environment]::SetEnvironmentVariable("DOW", $dow, "Machine")

or

[Environment]::SetEnvironmentVariable("DOW", $dow, "User")

By the way, your script doesn't work because all you're getting is the PowerShell return code, not the data it produces. There may be a way to get it to work, but it's ultimately pointless compared to just using a proper PowerShell script.

For completeness, here is a nice article from Microsoft on PowerShell and environmental variables:

Creating and Modifying Environment Variables

Update: Having reviewed this solution with @syneticon-dj in chat, it appears the issue you face using this method is that a command prompt has to be reloaded before it will reflect changes in environmental variables that have happened externally.

You haven't provided much detail about what it is you're doing, but if this is the only reason you're launching PowerShell, than my actual suggestion would to review how you're doing things.

Either do your whole process using PowerShell or have you considered using scheduled tasks instead? You can schedule tasks based on the day of the week.

Peter Mortensen
  • 2,319
  • 5
  • 23
  • 24
Dan
  • 15,280
  • 1
  • 35
  • 67
  • The batch file will be run every day and is run from the scheduled tasks. Im thinking of working in powershell instead. But im even more newbie in powershell than cmd. And right now Im having difficulties with a simple command. But I can make a new question about that one, maybe that's an easy one for you :) EDIT: I've figured it out. It was how to run a program with some parameters. – Tim Jan 13 '12 at 12:22
  • I'm not great at PowerShell, either, but it's well worth learning. For a start it's just better in almost every way, but it's also the way Microsoft (And so other manufacturers) are moving. – Dan Jan 13 '12 at 12:24
  • 1
    Also, note that @Dan's suggestion above sets the environment variables quite permanently (either in the Machine or User context). If you leave out the third parameter, you can set it for just the current process, which is sometimes more desirable. – Per Lundberg Oct 25 '13 at 06:28
20

I believe setting the environment variable from within PowerShell with [Environment]::SetEnvironmentVariable as suggested by Dan is pointless, because you would either lose the variable's content upon the termination of PowerShell if you chose the temporary "process" context or would not have it within your batch file's environment yet if you chose the permanent "machine" or "user" context - that is, unless your entire script is written in PowerShell, where the problem would not arise in the first place:

C:\Users\myuser> echo %DOW%
%DOW%

C:\Users\myuser> powershell
Windows PowerShell
Copyright (C) 2009 Microsoft Corporation. Alle Rechte vorbehalten.

PS C:\Users\myuser> $dow = (get-date).dayofweek
PS C:\Users\myuser> [Environment]::SetEnvironmentVariable("DOW", $dow, "User")
PS C:\Users\myuser> [Environment]::SetEnvironmentVariable("DOW", $dow, "Process")
PS C:\Users\myuser> exit

C:\Users\myuser> echo %DOW%
%DOW%

C:\Users\myuser>

You could use the for command as a workaround to parse the output of your PowerShell command and put it into a variable:

  for /F "usebackq tokens=1" %%i in (`powershell ^(get-date^).dayofweek`) do set DOW=%%i

Note the caret characters ^ used to escape the parenthesis special characters within your PowerShell call.

If you are testing it from the command line and not from within a batch file context, you would need to replace the %% before variable references by %:

C:\Users\myuser> for /F "usebackq tokens=1" %i in (`powershell ^(get-date^).dayofw
eek`) do set DOW=%i

C:\Users\myuser> set DOW=Friday

C:\Users\myuser>
Peter Mortensen
  • 2,319
  • 5
  • 23
  • 24
the-wabbit
  • 40,319
  • 13
  • 105
  • 169
  • No, this is incorrect. My example below sets 'normal' Environmental variables which are accessible from any batch file etc. – Dan Jan 13 '12 at 10:19
  • @Dan I believe you are mistaken, I've tried setting `[Environment]::SetEnvironmentVariable("DOW", $dow, "user")` from within a running powershell session but it was not present in my parent cmd session upon termination of PowerShell – the-wabbit Jan 13 '12 at 10:22
  • The formatting has screwed that up, but you haven't defined $dow. Running my example in a Powershell script stores a normal environmental variable as expected. – Dan Jan 13 '12 at 10:26
  • @Dan I have. And obviously the environment variable is stored **for the powershell process** but it is isolated from the parent CMD process and cannot be accessed there. Just test it and see. – the-wabbit Jan 13 '12 at 10:28
  • 1
    @Dan BTW: I do not mind the downvoting, but it should be noted that the demonstrated approach **clearly does what the questioner has asked for**, so even if there were a more elegant approach, it still would be a valid solution to the problem. – the-wabbit Jan 13 '12 at 10:31
  • I'm not sure what to say - it unequivocally works here. The Powershell internal environmental variables are created by $env:VariableNameHere - read the link I posted – Dan Jan 13 '12 at 10:32
  • let us [continue this discussion in chat](http://chat.stackexchange.com/rooms/2196/discussion-between-syneticon-dj-and-dan) – the-wabbit Jan 13 '12 at 10:36
  • 1
    @the-wabbit That sounds like normal behavior in Windows. Even if you update the global environment variables, only processes started *since the update* will recognize the change. Since you're talking about a *parent* process, it must have started before the change. The same thing happens with `SET` in Command Prompt. Try starting a child `cmd.exe` and you'll see the same thing. The behavior you're seeing *in* PowerShell though is because updating the environment variables through the .NET classes doesn't affect the current process, though. – jpmc26 Jun 23 '16 at 22:07
  • @jpmc26 this is what I was trying to point out. You cannot set an environment variable for the parent process. So the only way to achieve what the OP is asking for would be to pass the desired value in the output of the powershell script and parse the output in the parent batch to assign it to the desired environment variable. – the-wabbit Jun 24 '16 at 07:24
  • @dan : the-wabbit is right: the `powershell` process (child process) is started by the `cmd` proces (parent process), and there is no technical option for the child process (powershell) to "inject" a environment variable its parent process (cmd). – t0r0X Aug 23 '19 at 18:27
4

If it were me, and the parent script has to be a shell script, I'd just do a cheeky invocation of PowerShell in the .CMD script like:

set DOW=
for /f %%D in ('%SystemRoot%\System32\WindowsPowerShell\V1.0\powershell.exe -NoLogo -NoProfile -Command Write-Host -Object ^(Get-Date^).DayOfWeek;') do set DOW=%%D

You might need to check your PowerShell execution policy (Set-ExecutionPolicy cmdlet).

Simon Catlin
  • 5,222
  • 3
  • 16
  • 20
2

Or if you're married to doing this in the old shell, skip PowerShell entirely.

Use the %date% variable and expand out the day from the abbreviation it gives (this might be affected by regional date format settings):

C:\> echo %date%
Thu 09/05/2013

Grab the first token in the answer and expand on that:

C:\> type dayofweek.cmd
@echo off
for /f %%A in ("%date%") do set DAYOFWEEK=%%A
if "%DAYOFWEEK%" == "Mon" set DAYOFWEEK=Monday
if "%DAYOFWEEK%" == "Tue" set DAYOFWEEK=Tuesday
if "%DAYOFWEEK%" == "Wed" set DAYOFWEEK=Wednesday
if "%DAYOFWEEK%" == "Thu" set DAYOFWEEK=Thursday
if "%DAYOFWEEK%" == "Fri" set DAYOFWEEK=Friday
if "%DAYOFWEEK%" == "Sat" set DAYOFWEEK=Saturday
if "%DAYOFWEEK%" == "Sun" set DAYOFWEEK=Sunday
echo.%DAYOFWEEK%
C:\>
C:\> dayofweek
Thursday
Peter Mortensen
  • 2,319
  • 5
  • 23
  • 24
1

Actually, when putting something like the below in a .ps1 file (say, t.ps1) and calling it from a CMD session with PowerShell -File t.ps1 ... it works well.

$DateAndTime = (get-date -UFormat "%Y%m%d_%H%M%S")[Environment]::SetEnvironmentVariable("DateAndTime", $DateAndTime, "Machine")

But not for the CMD session where the t.ps1 script has been called from. In a new CMD session we get:

D:> echo %DateAndTime% ==> 20120208_123106

I guess we have to find out how to get done something like export T=date in a CMD session.

Peter Mortensen
  • 2,319
  • 5
  • 23
  • 24
Edgar
  • 11
  • 1
0

If you want that your batch file to access environment variables that are set by a PowerShell command run from that batch file, you can use the following workaround:

Make your PowerShell script create a sub batch file, mysub.bat, that contains "set variable=value" lines, and execute that mysub.bat batch file from the main batch file right after the PowerShell command.

Use the WriteAllLines method rather than the default PowerShell output methods so that the sub batch file be not generated with the UTF-8 encoding format.

Example

main.bat:

REM main.bat first line
powershell -Command "[System.IO.File]::WriteAllLines(\".\mysub.bat\", \"set VARIABLE=VALUE\");"
.\mysub.bat
echo VARIABLE=%VARIABLE%
REM expected output: VARIABLE=VALUE