I have a need within a .bat file to change to a certain directory which is referenced by an environment variable. Something along these lines:
cd %TMP%
And this works fine from Windows CMD shell. However if I try to run the bat within a Powershell terminal window, it appears that the command simply doesn't work. This does though:
cd $Env:TMP
So I'm trying to figure out how to keep things to one .bat file but still allow users to run it under both the CMD prompt and the PS prompt. I can think of some hacky ways to check to see if I'm under CMD (as opposed to PS) but I'd like to know if there's a better solution.
One thing I noticed is that the PROMPT environment variable is present with CMD but not with Powershell but, as I say, that seems a bit hacky and potentially error-prone.
I'm not trying to pad my rep so if this has already been asked and answered, please point me to it. I just want to find something less hacky than trying to figure out which shell the bat is being run in and changing the cd command to suit it.
By the way, since it may make a difference, I'm running under Powershell 4. I could probably use a .cmd file if that would make any difference but I'd be surprised if it did.
EDIT:
I guess maybe I wasn't as clear as I could be. I'm trying to figure out if there's a way to get the value of an environment variable that will work within a .bat file that will work regardless of whether or not the .bat file is run under the cmd shell or the powershell shell.
Running batch files from PowerShell works just fine. However, since the batch files run in a different interpreter (running .\your.bat is basically the same as running cmd /c .\your.bat), changing the working directory via cd %TMP% in the (CMD) child process doesn't change the working directory for the (PowerShell) parent process.
The syntax you use for variables in batch files is always %variable%.
Demonstration:
PS C:\> $PWD.Path
C:\
PS C:\> Get-Content .\test.bat
#echo off
echo before: %CD%
cd %TMP%
echo after: %CD%
PS C:\> .\test.bat
before: C:\
after: C:\Users\me\AppData\Local\Temp
PS C:\> $PWD.Path
C:\
The batch file echoes the path of the current working directory (%CD%) before and after changing the working directory to %TMP%. The working directory of the parent process (PowerShell) remains unchanged ($PWD.Path).
Related
I saw some surprising behavior in powershell recently.
Consider the script c:\scripts\tst1.ps:
Set-location c:\
Now from powershell:
C:\scripts PS> .\tst1.ps1
C:\ PS>
Why does the calling shell change to “C:\” according to “set-location”? shouldnt the “set-location” run from a subshell according to normal scripting rules for other shells like bash?
I thought that you had to “dot source” the script to get this type of behavior??? That is: “. .\tst1.ps1”? What is happening here.
is my powershell misconfigured on my host computer or is this the actual behavior of powershell these days?
Is there a way to reconfigure powershell to get the old behavior that I expect that is similar to bash shell where the script runs in a sub shell and exits and the current directory is uneffected?
You can run your script with the new instance of powershell:
C:\scripts PS> powershell .\tst1.ps1
I don't use powershell often, so this may be an obvious question but my google-fu is failing me.
What is the difference between running the following commands, on a Windows platform?
In cmd prompt:
C:\> powershell cd d:\foo
and in powershell prompt:
PS C:\> cd d:\foo
The latter changes drive and directory as expected. The former does nothing.
Basically, when you run powershell cd d:\foo it opens a separate Powershell and runs the cd command. As opposed to the second one, you are actually in the Powershell session. So it, the first one, does open a Powershell process > change the directory and then it closes the process.
I have a PowerShell script which contains a single command:
pwd
When I execute it from a (Windows 10) command line window, I get the following:
d:\Hudson_Test\workspace\CadGraphics>echo %cd%
d:\Hudson_Test\workspace\CadGraphics
d:\Hudson_Test\workspace\CadGraphics>powershell -file ShowLocation.ps1
Path
----
D:\hudson_test\workspace
As you can see, the current directory moves up one directory (from d:\hudson_test\workspace\CadGraphics to D:\hudson_test\workspace) when inside the PowerShell script.
I tested this on another (Win10) machine, and on that machine, the two paths were the same.
What is going on here, and how can I keep it from happening?
It should not unless the Profile is loading it everytime. Please try with
powershell -NoProfile -File FileName.ps1
Secondly , I would like you to store that in a variable and see the result from write-host
I am creating a standard windows BAT/CMD file and I want to make an IF statement to check whether or not this CMD file is run from PowerShell. How can I do that?
Edit: My underlying problem was that test.cmd "A=B" results in %1==A=B when run from CMD but %1==A and %2==B when run from PowerShell. The script itself is actually run as an old Windows Command line script in both cases, so checking for Get-ChildItem will always yield an error.
One way, it to see what your process name is, and then check its attributes:
title=test
tasklist /v /fo csv | findstr /i "test"
As long as you use a unique name in place of Test, there should be little room for error.
You will get back something like:
"cmd.exe","15144","Console","1","3,284
K","Running","GNCID6101\Athomsfere","0:00:00","test"
When I ran the above code from a bat file, my output was:
"powershell.exe","7396","Console","1","50,972
K","Running","GNCID6101\Athomsfere","0:00:00","
A potentially simpler approach that may work for you. If not, it may be suitable for others.
Create 2 separate script files: test.ps1 and test.cmd
Don't include extension when calling the script. I.e. call as <path>\test (or just test if folder is in the path environment variable.
This works because CMD prioritises which script to execute as: .bat > .cmd, whereas Powershell prioritises: .ps1 > .bat > .cmd.
The following is the output of a CMD session:
C:\Temp>copy con test.cmd
#echo cmd^Z
1 file(s) copied.
C:\Temp>copy con test.ps1
Write-Output "ps1"^Z
1 file(s) copied.
C:\Temp>.\test
cmd
C:\Temp>
And calling test from Powershell:
PS C:\Temp> .\test
ps1
PS C:\Temp>
Couldn't you try to execute a Get-ChildItem and then check %ERRORLEVEL% to see if it returns an exe not found?
http://ss64.com/nt/errorlevel.html
I read some file using PowerShell, and change current dir accordingly, but all I can do is change the current PowerShell's current dir, not the caller's dir (the cmd.exe environment that called that ps1 file). Things I tried:
powershell ch-dir.ps1 | cd
(won't work, obviously, since CD is internal command)
powershell cd $myDir
(changes current dir in PowerShell, but when script exits, the cmd environment still in original dir)
I really hope I won't need to find the script's caller process (the cmd), and make a change in it's cur-dir by-force... (or even worse - to save the dir I want in some env-var and then cd %my_var% since it would require two lines of command)
I'm not sure if this meets your needs, but if you set it up so that the only output from your powershell script is your desired new working directory, you could do this:
c:\>for /F %i IN ('powershell -noprofile -command "write-output 'c:\users'" ') DO #cd %i
c:\Users>
The cmd prompt is hosting your powershell session, unless you can figure out a way to return an exit code to the prompt that will (on exit code 99999) change directory to (predefined values, switch?). As far as powershell is concerned they're different processes.
Heres a good example for you to try:
Open a cmd prompt.
Open task manager, find cmd.exe
In your cmd prompt type Powershell
View powershell as a different process (check the PID.)
End the powershell process. Watch what happens.
Alternatively, if you need something run from cmd in a specific directory based on logic in your powershell script, you can invoke it with a cmd /c from within Powershell.