Why does command work in Windows CMD and not PowerShell? - powershell

I have a script that saves an executable and a .ps1 to a list of remote computers.
It then runs the executable on each computer.
I have to call the executable with a .ps1 because of the way it is set up when running silently.
I noticed that one of my commands runs quickly from the command line but seems to hang up in my script. Is there any reason why this would happen?
The command is:
psexec -s #C:\myscript\computers.txt cmd /c "Powershell Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass && PowerShell -noninteractive -file "C:\Install.ps1""
Here is my entire script:
cls #clear screen
function CopyFiles {
# Get .exe from source and place at destination workstation
$source2="\\mainserver\program.exe"
$destination2="\\$line\c$\program.exe" # place .exe on C:\ directory of worstation
Copy-Item -Recurse -Filter *.* -path $source2 -destination $destination2 -Force
# Get .bat from source and place at destination workstation
$source3="\\fileserver\Install.ps1"
$destination3="\\$line\c$\Install.ps1" # place .bat on C:\ directory of worstation
Copy-Item -Recurse -Filter *.* -path $source3 -destination $destination3 -Force
}
$a = Get-Content "C:\myscript\computers.txt"
foreach($line in $a)
{
"These options must run in numbered order."
" "
" "
"1. Copy installer to remote computer(s)."
"2. Remove application from remote computer(s)."
"3. Install application from remote computer(s)."
"4. Quit."
" "
"Type number and press Enter."
$UI = Read-Host -Prompt ' '
If ($UI -eq 1) {
CopyFiles
} ELSEIF ($UI -eq 2) {
psexec #C:\myscript\computers.txt -c "\\fileserver\Remove.bat"
} ELSEIF ($UI -eq 3) {
psexec -s #C:\myscript\computers.txt cmd /c "Powershell Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass && PowerShell -noninteractive -file "C:\Install.ps1""
} ELSEIF ($UI -eq 4) {
"Good Bye"
}
}

The root cause is because PowerShell has a more standard rule to parse parameters which is different from cmd. In PowerShell if a parameter starts with a quote then it'll also end with the quote. However in cmd the parameter continues if there are no separator (like space or tab) after the quote. That means "powershell someargs "another"" is 2 parameters in PowerShell but only 1 in cmd. Try echoing the command from PowerShell and you'll see that right away
PS D:\> echo psexec -s #C:\myscript\computers.txt cmd /c "Powershell Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass && PowerShell -noninteractive -file "C:\Install.ps1""
psexec
-s
#C:\myscript\computers.txt
cmd
/c
Powershell Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass && PowerShell -noninteractive -file
C:\Install.ps1
C:\Install.ps1 is split to a different argument, compared to cmd where it's recognized as one:
D:\>type testparam.bat
#echo off
:loop
if [%1]==[] exit /b
echo [%1]
shift
goto :loop
D:\>testparam.bat psexec -s #C:\myscript\computers.txt cmd /c "ps -ExecutionPolicy Bypass AND ps -noninteractive -file "C:\Install.txt""
[psexec]
[-s]
[#C:\myscript\computers.txt]
[cmd]
[/c]
["ps -ExecutionPolicy Bypass AND ps -noninteractive -file "C:\Install.txt""]
As you can see the middle quotes aren't nested quotes and are leaved as-is to the command, then cmd /c will have another weird behavior: stripping the first and last quote and run the remaining things as one command
PowerShell also strips double quotes but only the outer one of each parameter and before passing to the command
Now to fix that you have to include double quote in the parameter by using either of these
psexec -s #C:\myscript\computers.txt cmd /c "Powershell Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass && PowerShell -noninteractive -file ""C:\Install.ps1"""
psexec -s #C:\myscript\computers.txt cmd /c "Powershell Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass && PowerShell -noninteractive -file `"C:\Install.ps1`""
psexec -s #C:\myscript\computers.txt cmd /c '"Powershell Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass && PowerShell -noninteractive -file "C:\Install.ps1"'
psexec -s #C:\myscript\computers.txt cmd /c --% "Powershell Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass && PowerShell -noninteractive -file "C:\Install.ps1""
Or if the file path doesn't have any spaces you can simply remove them which will work in both cmd and PowerShell
psexec -s #C:\myscript\computers.txt cmd /c "Powershell Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass && PowerShell -noninteractive -file C:\Install.ps1"
In fact if the path contain spaces like "C:\some dir\Install.ps1" then your command will fail in both cmd and PowerShell because now cmd also splits the part after the space to a new argument. Try this and see
psexec -s #C:\myscript\computers.txt cmd /c "Powershell Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass && PowerShell -noninteractive -file "C:\some dir\Install.ps1""

Related

Run Powershell 7 from CMD

I have a .bat script that runs Powershell as Admin and then runs a Powershell script in the same folder as the .bat file. This works perfectly fine:
CMD /C powershell "Set-Location -PSPath '%CD%'; $Path =
(Get-Location).Path; Set-Location ~; Start powershell -Verb RunAs -Args
"-ExecutionPolicy ByPass" Set-Location -PSPath '"$Path"'; &
'".\Start_TOW_VM.ps1"'"""
I am now trying to use Powershell 7 (pwsh) instead and I thought it'd be as simple as changing to this:
CMD /C pwsh "Set-Location -PSPath '%CD%'; $Path = (Get-Location).Path;
Set-Location ~; Start pwsh -Verb RunAs -Args "-ExecutionPolicy
ByPass" Set-Location -PSPath '"$Path"'; & '".\Start_TOW_VM.ps1"'"""
Unfortunately, it doesn't work and complains about the Set-Location command, even though that command works perfectly fine in Powershell 7. What am I doing wrong here?
Figured it out, here's the solution:
CMD /C pwsh -c Set-Location -PSPath '%CD%'; $Path =
(Get-Location).Path; Set-Location ~;write-host $path; start pwsh -Verb
RunAs "-command Set-ExecutionPolicy ByPass;
Set-Location -PSPath '"$Path"'; & '".\Start_TOW_VM.ps1"'"
Simply needed to add -command inside the escaped ".

Run a powershell command as administrator in a bat file

I have this powershell command that must run as administartor in powershell. I want to run as a batch file as administator. Would you please help me?
Get-AppxPackage -allusers ContentDeliveryManager | foreach {Add-AppxPackage "$($_.InstallLocation)\appxmanifest.xml" -DisableDevelopmentMode -register }
To avoid the problem of double/double quote, i suggest you to put your command in a script.ps1 then do this command:
PowerShell -windowstyle hidden -NoProfile -ExecutionPolicy Bypass -Command "& {Start-Process PowerShell -windowstyle hidden -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File ""YourScript.ps1""' -Verb RunAs}"
Try this batch
<# : batch script
#echo off
cd /D "%~dp0"
if not "%1"=="am_admin" (powershell start -verb runas '%0' am_admin & exit /b)
setlocal
cd %~dp0
powershell -executionpolicy remotesigned -Command "Invoke-Expression $([System.IO.File]::ReadAllText('%~f0'))"
endlocal
goto:eof
#>
# here write your powershell commands...
Get-AppxPackage -allusers ContentDeliveryManager | foreach {Add-AppxPackage "$($_.InstallLocation)\appxmanifest.xml" -DisableDevelopmentMode -register }
save it as .bat or .cmd and run it.
You can run it like this:
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -Command ""& {Get-AppxPackage -allusers ContentDeliveryManager | foreach {Add-AppxPackage ""$($_.InstallLocation)\appxmanifest.xml"" -DisableDevelopmentMode -register }"" -Verb RunAs}"
UPDATE
Fixed double quotes

How can i put my credentials in an batch file with powershell scripting in it

#ECHO OFF
echo start powershell
call powershell.exe -ExecutionPolicy ByPass -Command "$null=Install-Script -Name Get-WindowsAutoPilotInfo -force"
call powershell.exe -ExecutionPolicy ByPass -Command "& $env:ProgramFiles\WindowsPowerShell\Scripts\Get-WindowsAutoPilotInfo.ps1 -online
This is the .bat file. At the Get-Windowsautopilotinfo.ps1 -online I am asked to enter my credentials twice. Can I automate this process?

Run powershell commands from cmd / batch

I would like to run the following as administrator:
PowerShell -NoProfile -ExecutionPolicy Unrestricted -Command
.\Get-WindowsAutoPilotInfo.ps1 -ComputerName $env:computername
-OutputFile .\computers.csv -append
I would like to simply double click on a .cmd or .bat file and have it invoke the Powershell script as administrator. Here's what I have:
PowerShell "SL -PSPath '%CD%'; $Path = (GL).Path; SL ~; Start
PowerShell -Verb RunAs -Args \"-ExecutionPolicy Unrestricted -Noexit"
SL -PSPath '"$Path"'; & '".\UninstallBloatware.ps1" "-ComputerName
$env:computername" "-OutputFile .\computers.csv" "-append"' "\""
I copied most of the code above from somewhere I can't remember. I don't know enough about quotes structure to know how to fix this. Any ideas what I'm doing wrong?

Starting an admin shell then executing multiple commands

I have a powershell script and a bat file that launches it. I want the bat file to open powershell, then have powershell start another shell with elevated privileges, then run two commands. First command is change directory, second command is start a powershell script.
So far I have this:
powershell -NoProfile -ExecutionPolicy ByPass -Command "& {Start-Process PowerShell -Verb RunAs -ArgumentList '-NoExit -NoProfile -ExecutionPolicy Bypass cd %~dp0 .\App\Deploy-Application.ps1}'"
This is the section I'm having problems with:
cd %~dp0 .\App\Deploy-Application.ps1
I want to run these two commands but I'm not sure how. It runs a single command. I tried adding a semicolon between the commands but it didn't work.
Made a quick test and this is what i got working:
Test.bat
cd %~dp0
powershell -NoProfile -Command ".\test.ps1"
Test.ps1
If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
{
$arguments = "-noprofile & '" + $myinvocation.mycommand.definition + "'"
Start-Process powershell -Verb runAs -ArgumentList $arguments
Break
}
Write-Host "Rawr"
Pause
If i run the batch file, it opens the powershell script that then checks if the current window is being run as an administrator and if not, reopens the script as an administrator.
After which it displays Rawr on my screen.
In your case instead of the Write-Host you could put
If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
{
$arguments = "-noprofile & '" + $myinvocation.mycommand.definition + "'"
Start-Process powershell -Verb runAs -ArgumentList $arguments
Break
}
cd <Your directory to change to here>
<run command here>
Pause