Start-Process powershell cannot find specified - powershell

Edit5: Adam's code works unless there are spaces in the path. That solution is at Powershell Opening File Path with Spaces
Edit4: Simplified further with a test for the path. Same Error.
If ($args[0] -eq "admin")
{
$TheScriptPath = "C:\Users\root\Desktop\script.ps1"
Test-Path ($TheScriptPath)
Start-Process "powershell -noexit" $TheScriptPath
}
Else { Write-Host "OK" }
Output when I call "powershell .\script.ps1 admin" is:
True
Start-Process : This command cannot be run due to the error: The system cannot find the file specified.
At C:\Users\root\Desktop\script.ps1:11 char:2
Edit3: Nevermind. Previous solution stopped working. Script is:
if ($args[0] -eq "admin)
{
$TheScriptPath = $myInvocation.MyCommand.Definition
Start-Process powershell -Verb runAs -Workingdirectory $PSScriptroot $TheScriptPath
exit
}
Write-Host "Ok"
Error when I call "powershell .\script.ps1 admin" is:
Start-Process : This command cannot be run due to the error: The system cannot find the file specified.
At C:\Users\root\Desktop\script.ps1:11 char:2
It's not even working when I hard-code the script path now, even with "-Verb runAs" removed.
Edit2: This is solved, I just can't accept my own answer for two days. Hopefully I remember to do that in case someone else comes along with this question.
Edit1: My script now reads:
If ($args[0] -eq "go")
{
$ThePath = $myInvocation.MyCommand.Definition
Start-Process powershell -Verb runAs $ThePath
Exit
}
Write-Host "OK"
It fails with the error below. However, if I hard-code the script path and write the script as:
If ($args[0] -eq "go")
{
Start-Process powershell -Verb runAs C:\Users\root\Desktop\script.ps1
Exit
}
Write-Host "OK"
It succeeds. I've also tried ""$myInvocation.MyCommand.Definition"" to no avail.
Original:
I have a powershell script that, at least in Windows 7, elevated the user and then ran the rest of the script. In Windows 10, however, it's giving me:
Exception calling "start" with "1" argument(s): "The system cannot find hte file specified"
At C:\Users\root\desktop\script.ps1:15 char:2
If ($True)
{
# We are not running "as Administrator" - so relaunch as administrator
# Create a new process object that starts PowerShell
$newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell";
# Specify the current script path and name as a parameter
$newProcess.Arguments = $myInvocation.MyCommand.Definition;
# Indicate that the process should be elevated
$newProcess.Verb = "runas";
# Start the new process
[System.Diagnostics.Process]::Start($newProcess);
# Exit from the current, unelevated, process
exit
}
Write-Host "Ok"
The script exists at this path, as it actually attempting to invoke itself. I'm at a loss here.

I'm running Powershell v5.1.15063.1155 on Windows 10 (v10.0.15063 Build 15063). If I run the following:
$context = [Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()
if (-not $context.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Start-Process powershell -Verb runAs -ArgumentList $myInvocation.MyCommand.Definition
exit
}
Get-Date
Sleep -Seconds 4
You can try this as a workaround as it works for me.
To your question, I'd think something is wrong with the the ProcessStartInfo object you created ($newProcess). I've seen that error when the executable name supplied as a parameter can't be found. For example, if I run the following:
$newProcess = new-object System.Diagnostics.ProcessStartInfo "cocain";
$newProcess.Arguments = $myInvocation.MyCommand.Definition;
$newProcess.Verb = "runas";
[System.Diagnostics.Process]::Start($newProcess);
I get the error you described:
You're sure Powershell is in your path (where.exe powershell)? I know its a reach.

Related

How To Capture Output from Non-elevated Process Run from Elevated Powershell

I'm trying to update an elevated PowerShell script that's using StartProcess on a BAT file that runs RunAs on PowerShell.exe to run another PowerShell script without elevation in order to clone a git repository so that the directory is created in a way that a normal non-elevated user will be able to use.
Elevated PS1: Start-Process
=> Elevated .BAT: RunAs /trustlevel:0x20000
=> Non-elevated PS1
This is failing in some environments and I can't figure out why so I'm trying to figure out how to capture stdout and stderr from all levels of this process, but I'm not seeing the error or any output. I can capture it down to the BAT file level, but I can't seem to see anything that's happening within the inner-most Powershell script.
This seems like an awful lot of work just to programmatically clone a Git repository from an elevated process. Is there a way to make this work or is there an easier way?
EDIT: Just learned that this solution was broken as of Windows 11 Update 22H2: https://superuser.com/questions/1749696/parameter-is-incorrect-when-using-runas-with-trustlevel-after-windows-11-22h2
but the workaround is to use the /machine switch when running RunAs.
I suggest simplifying your approach as follows:
Use synchronous invocation of runas.exe, via Start-Process -Wait, which obviates the need for an intermediate batch file, and the need for a named pipe (System.IO.Pipes.NamedPipeClientStream)
Let the runas.exe-launched PowerShell child process that runs test2.ps1 capture that script's output in a temporary file, which you can read after the Start-Process -Wait call returns.
test2.ps1 can then just produce output normally - no need for System.IO.Pipes.NamedPipeClientStream
Elevated PowerShell Script (test.ps1):
function IsAdmin{
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
$Is64 = [Environment]::Is64BitOperatingSystem
if ($currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Output "Running with elevated privileges. (64-bit=$Is64)"
} else {
Write-Output "Running without elevated privileges. (64-bit=$Is64)"
}
}
IsAdmin
# Create a temporary file in which to capture the output from the
# PowerShell child process launched by runas.exe.
$outFile = New-TemporaryFile
# Use Start-Process -Wait to directly invoke runas.exe,
# which doesn't just wait for runas.exe ITSELF to exit, but also
# waits for its CHILD processes.
# This ensures that execution is blocked until the other PowerShell script exits too.
Start-Process -Wait runas.exe #"
/machine:amd64 /trustlevel:0x20000 "powershell -c & \"$PSScriptRoot\test2.ps1\" -drive C:\ *> \"$outFile\""
"#
# Now $outFile contains all output produced by the other PowerShell script.
Write-Verbose -Verbose "Output from the runas.exe-launched PowerShell script:"
Get-Content -LiteralPath $outFile
$outFile | Remove-Item # Clean up.
Non-Elevated PowerShell Script (test2.ps1):
param([string]$drive)
function IsAdmin{
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
$Is64 = [Environment]::Is64BitOperatingSystem
if ($currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Output "Running with elevated privileges. (64-bit=$Is64)"
} else {
Write-Output "Running without elevated privileges. (64-bit=$Is64)"
}
}
function Setup-Test{
Write-Output "Testing Powershell with Parameter Drive=$drive"
git config --global user.name
cd bob
Write-Error "Error Line 1
Error Line 2"
Write-Error "Error Line 3"
$d = 3/0
Write-Output "Done Testing Powershell"
}
IsAdmin
Setup-Test
This can be solved with a named pipe.
Elevated PowerShell Script (test.ps1)
function IsAdmin{
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
$Is64 = [Environment]::Is64BitOperatingSystem
if ($currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Output "Running with elevated privileges. (64-bit=$Is64)"
} else {
Write-Output "Running without elevated privileges. (64-bit=$Is64)"
}
}
IsAdmin
Write-Output "Running $PSScriptRoot\test.bat"
Start-Process -FilePath "$PSScriptRoot\test.bat" -ArgumentList "C:\" -NoNewWindow
$np = new-object System.IO.Pipes.NamedPipeClientStream('.','SAMPipe', [System.IO.Pipes.PipeDirection]::In,[System.IO.Pipes.PipeOptions]::None,[System.Security.Principal.TokenImpersonationLevel]::Impersonation)
$np.Connect()
$sr = new-object System.IO.StreamReader($np)
while ($l=$sr.ReadLine()) {
Write-Output $l
}
$sr.Close()
$np.Close()
BAT file in the middle to de-elevate (test.bat)
runas /machine:amd64 /trustlevel:0x20000 "powershell -command %~dp0test2.ps1 -drive %1 >dummy.txt"
Non-Elevated PowerShell Script (test2.ps1)
param([string]$drive)
function IsAdmin{
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
$Is64 = [Environment]::Is64BitOperatingSystem
if ($currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Output "Running with elevated privileges. (64-bit=$Is64)"
} else {
Write-Output "Running without elevated privileges. (64-bit=$Is64)"
}
}
function Setup-Test{
Write-Output "Testing Powershell with Parameter Drive=$drive"
git config --global user.name
cd bob
Write-Error "Error Line 1
Error Line 2"
Write-Error "Error Line 3"
$d = 3/0
Write-Output "Done Testing Powershell"
}
$np = New-Object System.IO.Pipes.NamedPipeServerStream('SAMPipe',[System.IO.Pipes.PipeDirection]::Out)
$np.WaitForConnection()
$sw = New-Object System.IO.StreamWriter($np)
$sw.WriteLine('Begin Non-Elevated Process Pipe')
Invoke-Command -ScriptBlock {
try {
IsAdmin
Setup-Test
} catch {
Write-Error $_
}
} -ErrorVariable errVar -OutVariable out
foreach ($line in $out){
$sw.WriteLine($line)
}
foreach ($line in $errVar) {
$sw.WriteLine($line)
}
$sw.WriteLine('End Non-Elevated Process Pipe')
$sw.Close()
$np.Close()
Output
Running with elevated privileges. (64-bit=True)
Running C:\Users\bmarty\source\PowerShellTest\test.bat
C:\Users\bmarty\source\PowerShellTest>runas /machine:amd64 /trustlevel:0x20000 "powershell -command C:\Users\bmarty\source\PowerShellTest\test2.ps1 -drive C:\ >dummy.txt"
Begin Non-Elevated Process Pipe
Running without elevated privileges. (64-bit=True)
Testing Powershell with Parameter Drive=C:\
Ben Marty
Cannot find path 'C:\Users\bmarty\source\PowerShellTest\bob' because it does not exist.
Error Line 1
Error Line 2
Error Line 3
Attempted to divide by zero.
System.Management.Automation.RuntimeException: Attempted to divide by zero. ---> System.DivideByZeroException: Attempted to divide by zero.
--- End of inner exception stack trace ---
at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exception)
at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
Attempted to divide by zero.
Attempted to divide by zero.
End Non-Elevated Process Pipe
Done running
I don't understand why the output of git config only appears in the output if I include >dummy.txt in the BAT file.
Try working with ACLs instead. You can set that up on the parent directory so you don't even need to run the script in an elevated context.
Just set up a "gitclone" account that can write into the repository parent directory and then add the rest of the users as read+execute.
The rest will come automagically through inheritance.
Then run script as that "gitclone" user.

Powershell - how to check if installation is running in user or system context

I have packaged an application with the App Deployment Toolkit.
I install the application with the command:
Start-Process -FilePath $setupx64 -ArgumentList "/silent /install" -verb runas
That works. But only if the installation is running in the user context and not in the system context. If the installation runs in the system context (via SCCM) I need this command without the parameter -verb runas => otherwise it does not work
Start-Process -FilePath $setupx64 -ArgumentList "/silent /install"
How can I check in my script if the installation is started in the user context or in the system context?
Thank you!!
BR
Here is an example snippet of code to determine if the current security context is NT AUTHRORITY\SYSTEM:
if ($env:USERNAME -eq "$env:COMPUTERNAME$") {
# do the thing that's special for the system
}
else {
# do whatever you want for the user
}
Do you mean, "How can I tell if the user is running as Administrator or not?"
If so, the following code should work.
$StartProcessSplat = #{
FilePath = $setupx64
ArgumentList = #(
"/silent",
"/install"
)
}
$User = [Security.Principal.WindowsIdentity]::GetCurrent()
$isAdmin = (New-Object Security.Principal.WindowsPrincipal $User).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
If ($isAdmin) { $StartProcessSplat['verb'] = 'runas' }
Start-Process #StartProcessSplat

PowerShell keeps on saying network path not found

I created a simple PowerShell code that copies a folder from one computer to another, but I keep getting a "Network path not found" is there something I am doing wrong?
# PowerShell Read-Host Input Box
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs; exit }
Clear-Host
$ComputerName1 = Read-Host "What is the name of your computer?"
$ComputerName2 = Read-Host "What is the name of the computer you are fixing?"
$Yours = $ComputerName1
$Theirs = $ComputerName2
robocopy "\\$ComputerName1\c:\Temp\Test" "\\$ComputerName2\c:\Temp\"

Ignoring powershell script failure for a particular line

I have a powershell script that defines $ErrorActionPreference = "Stop"
But i also have a start-process call that target a process that returns a non-standard exit code on success (1 instead of 0).
As a result of this, the script is failing even when the start-process is ok.
I tried to append the -ErrorAction "Continue" parameter in the start-process call but it didn't solve the problem.
The problematic line looks like this:
$ErrorActionPreference = "Stop"
...
start-process "binary.exe" -Wait -ErrorAction "Continue"
if ($LastExitCode -ne 1)
{
echo "The executable failed to execute properly."
exit -1
}
...
How could I prevent start-process from making the whole script fail.
Start-Process doesn't update $LASTEXITCODE. Run Start-Process with the -PassThru parameter to get the process object, and evaluate that object's ExitCode property:
$ErrorActionPreference = "Stop"
...
$p = Start-Process "binary.exe" -Wait -PassThru
if ($p.ExitCode -ne 1) {
echo "The executable failed to execute properly."
exit -1
}

Powershell script running fine on Windows 8 but not on Windows 7

I am very new to powershell and I'm not sure what I did wrong. It is running fine on my Windows 8 PC but when I send it to someone else (he has Windows 7; created this for him), he gets a not allowed to run scripts error.
Tried with -ExecutionPolicy RemoteSigned but still no luck.
##################
<# CONFIG START #>
##################
#replace the path with your steam path. For example: C:\Program Files (x86)\Steam\Steam.exe
$steam_path = "C:\Program Files (x86)\Steam\steam.exe"
#You can change it to Ethernet 1 or Ethernet 2 or Ethernet 3 etc depending on which adapter you want to disable.
#If you have custom name for them (you can rename them from control panel), have to use that name.
$adapter_name = "Ethernet 1"
<#
What program to run.
1: Steam Dota 2
2: Steam CS
3: Steam CSS
4: Steam CSGO
5: Custom Program 1
6: Custom Program 2
7: Custom Program 3
#>
$game_id = "5"
<# Custom Program path and arguments#>
$cp1_path = "C:\Program Files (x86)\counter-strike source\css.exe"
$cp1_arg = " "
$cp2_path = ""
$cp2_arg = " "
$cp3_path = ""
$cp2_arg = " "
$delay = 20
################
<# CONFIG END #>
################
"Checking admin permissions..."
If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
{
"Administrator permissions required."
$arguments = '-ExecutionPolicy RemoteSigned -file "' + $myinvocation.mycommand.definition + '"'
# $arguments
Start-Process powershell -Verb runAs -ArgumentList $arguments
Break
}
"Exiting Steam..."
Start-Process -FilePath $steam_path -ArgumentList "-shutdown" -Wait:$true
Start-Sleep -s 2
"Disabling Network Adapter..."
Disable-NetAdapter -Name $adapter_name -Confirm:$false
Start-Sleep -s 5
"Starting Game..."
Switch($game_id)
{
1
{
Start-Process -filepath "steam://rungameid/570"
}
2
{
Start-Process -filepath "steam://rungameid/10"
}
3
{
Start-Process -filepath "steam://rungameid/240"
}
4
{
Start-Process -filepath "steam://rungameid/730"
}
5
{
Start-Process $cp1_path -ArgumentList $cp1_arg
}
6
{
Start-Process $cp2_path -ArgumentList $cp2_arg
}
7
{
Start-Process $cp3_path -ArgumentList $cp3_arg
}
}
Start-Sleep -s $delay
"Enabling Network Adapter..."
Enable-NetAdapter $adapter_name -Confirm:$false
exit
If you sent him the script, then RemoteSigned is doing it's job just fine. He got the script remotely (from you) and it is not signed, so it won't be executed.
Tell your friend to navigate to the ps1 script in Windows Explorer and right click, then choose "Unblock." He will then need to restart the PowerShell instance if it has failed to run the script already since this kind of information is cached by Windows.
The error indicates you didn't correctly set the execution policy. Firstly, you have run Powershell as an administrator. To do this, right click on the Powershell icon in the start menu and click on "Run as Administrator". Next you have to run the following command in Powershell:
Set-ExecutionPolicy RemoteSigned
You will be prompted to allow the change. Type "Y" and press return.
Finally, try running your script.