Set Executable's Working Directory When PowerShell Remoting - powershell

I'm using PowerShell remoting to execute an exe file on a remote server. The problem is that the exe needs to have its Working Directory set to the directory that the exe is in for it to run properly. If I run the exe locally (on the server) from a command prompt it works fine, and if I use Enter-PSSession (from my workstation) and then use Start-Process -FilePath [PathToExe] -WorkingDirectory [DirectoryPath] that works fine, but if I use Invoke-Command -ComputerName [Blah] -ScriptBlock [MyScriptBlock] or $session = New-PSSession -ComputerName [Blah]; Invoke-Command -Session $session -ScriptBlock [MyScriptBlock] (from my workstation) then the working directory does not get set.
This is what [MyScriptBlock] looks like:
$scriptBlock = {
param($version, $database)
$hubSyncronizerExeDirectoryPath = "C:\inetpubLive\ScheduledJobs\$version\"
$hubSyncronizerExePath = Join-Path $hubSyncronizerExeDirectoryPath 'Test.exe'
Set-Location -Path $hubSyncronizerExeDirectoryPath
Get-Location
Write-Output "$version $database"
Start-Process -FilePath $hubSyncronizerExePath -WorkingDirectory $hubSyncronizerExeDirectoryPath -ArgumentList '/database',$database
}
I've also tried using Invoke-Command instead of Start-Process, but it has the same effect; the Working Directory does not get set.
I've verified this by using the SysInternals Process Explorer, right-clicking on the process and choosing Properties. When I launch it locally or use Enter-PSSession, the Command Line and Current Directory properties are set, but not when using New-PSSession or just Invoke-Command with ComputerName.
I'm using both Set-Location and setting the -WorkingDirectory, which are the 2 typical recommended approaches for setting the working directory, and Get-Location does display the expected (server's local) path (e.g. C:\inetpubLive\ScheduledJobs\1.2.3.4). I'm guessing that this is just a bug with PowerShell (I'm using V4 on workstation and server), or maybe there's something I'm missing?
UPDATE
It turns out that the working directory was a red herring (at least, I think it was). For some reason everything works fine if I called my executable from a command prompt.
So in my Invoke-Command (I replaced Start-Process with Invoke-Command), changing this:
& ""$hubSyncronizerExePath"" /database $database
to this:
& cmd /c ""$hubSyncronizerExePath"" /database $database
fixed the problem.
Thanks for all of the suggestions guys :)

Try looking at New-PSDrive and see if that helps
I guess you'll want something like
New-PSDrive -Name WorkingDir -PSProvider FileSystem -Root "\\RemoteServer\c$\inetpubLive\ScheduledJobs\1.2.3.4"
CD WorkingDir:
I assume you should be able to amend your script to include and put in the $version variable in to the path on the New-PSDrive command...
Not certain this will do what you need it to do, but it's the first thing that sprang to mind...
Alternatively, try amending your script as follows:
$hubSyncronizerExeDirectoryPath = "\\remoteserver\C$\inetpubLive\ScheduledJobs\$version\"

Related

Run bat file via PowerShell

I am trying to run a batch file from remote computer but it also doesn't work locally
Invoke-Command -ComputerName $remoteComputer -ScriptBlock {
Start-Process "C:\Users\Administrator\Desktop\version\Installer\Installer.bat" -NoNewWindow -Wait
} -Credential $credentials -ErrorAction Stop
There is no errors but nothing happens
The installer.bat is located under C:\Users\Administrator\Desktop\version\Installer
The batch file contain setup.exe that also located at the same folder.
I am searching for hours the solution
For local I used this:
Start-Process "cmd.exe" "/c C:\Users\Administrator\Desktop\version\Installer\Installer.bat" -NoNewWindow
Seems that its working locally when i am going to the right folder (cd c:..)
and run
Invoke-Expression -Command 'cmd.exe /C C:\Users\Administrator\Desktop\version\Installer\Installer.bat'
So how can i do it remotely (I mean to go to the right path first)

Start-process: both positional parameter and can't locate file specified

Ok, So I am working on the powershell remote deployment of software to ADUsers.
I have remote access to the computer and all, no problems there.
Right now I am at the point where I have a exe file from Ninite to just install 7zip onto the client pc just to see when it works so i can start deploying some bigger programs to it.
The guide I have found to help me deploy out the software for now looks like this:
Invoke-Command -ComputerName *REDACTED* -Scriptblock {
Start-Process C:\Users\Administrator\Documents\ninite_7_zip\Ninite 7Zip Installer.exe '/silent' -wait
}
When I do run this code, I get the error:
A positional parameter cannot be found that accepts argument 'Installer.exe'.
So I thought to myself, that it might be because of the spaces in the name. So therefore I changed it to:
Invoke-Command -ComputerName *REDACTED* -Scriptblock {
Start-Process C:\Users\Administrator\Documents\ninite_7_zip\Ninite_7Zip_Installer.exe '/silent' -wait
}
And ofcourse also changed it's name within the folder to match the "newly made" code.
But the error now changed into:
This command cannot be run due to the error: The system cannot find the file specified
Even though I use Powershell ISE, and I used it's guideboxes when writing, to enter the folder and find it, when I wrote the directory.
My only goal in this, is that I want to remotely run and complete this installer on the client PC when deployed from the DC upon which the file lies.
Anybody got a qualified guess? Or maybe even so, a solution.
Thanks in advance for your kind answers.
When I do run this code, I get the error:
A positional parameter cannot be found that accepts argument 'Installer.exe'.
You'll want to use quotation marks to qualify path names with spaces in them:
Start-Process 'C:\Users\Administrator\Documents\ninite_7_zip\Ninite 7Zip Installer.exe' '/silent' -wait
But the error now changed into:
This command cannot be run due to the error: The system cannot find the file specified
Even though I use Powershell ISE, and I used it's guideboxes when writing, to enter the folder and find it, when I wrote the directory.
ISE is not smart enough to realize that the scriptblock is to be executed on a remote computer, so it completes the path based on your local file system.
You still need to copy the executable to the remote machine in order to execute it:
# first copy the installer to remote file system
$remoteSession = New-PSSession -ComputerName $computerName
$localInstaller = 'C:\Users\Administrator\Documents\ninite_7_zip\Ninite 7Zip Installer.exe'
$remotePath = Invoke-Command -Session $remoteSession -ScriptBlock { $env:TEMP }
Copy-Item $localInstaller -Destination (Join-Path $remotePath "7zInstaller.exe") -ToSession $remoteSession
# now we can invoke the executable on the remote machine (re-using the same remoting session)
Invoke-Command -Session $remoteSession -ScriptBlock {
Start-Process (Join-Path $env:TEMP "7zInstaller.exe") '/silent' -Wait
}
# clean up
$remoteSession |Remove-PSSession |Out-Null

Problem with msiexec and pssession in a script

I am attempting to write a powershell script which installs an .msi package. It takes user's input (client's IP and username) then creates a new PSSession and pulls the file from network drive.
Enter-PSSession -ComputerName $destination -Credential <xxxxxx>
Invoke-Command -ScriptBlock {msiexec /i "\\CLOUD_IP\road-to\msi-location\msi_to_install.msi"}
This is the main problem with the script. Once the script finishes, the installation prompts on my PC, not the client's, but it still stays in session. Until I exit the session either manually or via script.
Everything works as intended when I enter those two lines manually into powershell prompt.
I tried putting a Start-Sleep inbetween the two lines, since it takes a tad bit time for the Enter-PSSession, but that did nothing.
$destination is the user's IP input, which works as -ComputerName aswell, since Get-PSSession shows the IP as the computer name.
Change it to:
Invoke-Command -ComputerName $destination -Credential <xxxxxx> -ScriptBlock {msiexec /i "\\CLOUD_IP\road-to\msi-location\msi_to_install.msi" /qn /quiet /norestart}

Using PowerShell to execute a remote script that calls a batch file

I am having an issue with running a batch file that is located on a remote server.
I have a batch file located on a remote server that i want to run that kicks off an automated Selenium test. For simplicity, let's say the name of my batch file is mybatch.bat
I have the following code in a Powershell script located on the server:
$BatchFile = "mybatch.bat"
Start-Process -FilePath $BatchFile -Wait -Verb RunAs
If I run this PowerShell script locally on the server in ISE then it runs fine and it kicks off the selenium test which takes a couple minutes to run.
Now I want to try to execute this test from another machine by using PowerShell remoting. Let's assume that remoting is already configured on the servers.
I have a PowerShell script located on another server which has the following code segment. Assume that all of the session variables have the correct information set:
$CMD = "D:\mybatch.bat"
$TargetSession = New-PSSession -ComputerName $FullComputerName -Credential $myCreds -ConfigurationName RemoteExecution
$command = "powershell.exe -File $CMD -Wait"
Invoke-Command -Session $TargetSession -ScriptBlock { $command }
When this script runs, it does connect to the remote machine and create a remote session. It does look like it kicks off the batch file because PowerShell does not give me an error. But it does not wait for the full 3 or 4 minutes for the Selenium test to finish. It seems like it just times out. Also if I am logged onto the other machine, I don't see any Selenium web test running. No Selenium log files or results files are created on remote server as should be expected.
I was wondering what I could be doing wrong with my code.
Also, it seems that the server always returns the echo outputs of the batch file to my local machine. I see these random blinking white screen on ISE which looks like output from the batch file
$command = "powershell.exe -File $CMD -Wait"
Invoke-Command -Session $TargetSession -ScriptBlock { $command }
There are 2 issues with the above code:
$command inside the scriptblock and $command outside the scriptblock are different variables due to different scopes. The variable inside the scriptblock is thus undefined and the scriptblock will simply echo an emtpy value.
Even if $command weren't undefined, the scriptblock would still just echo its value, since it's defined as a string. PowerShell does not execute strings unless you're using something like Invoke-Expression (which you shouldn't).
This should do what you want:
$CMD = "D:\mybatch.bat"
$TargetSession = New-PSSession -ComputerName $FullComputerName -Credential $myCreds -ConfigurationName RemoteExecution
Invoke-Command -Session $TargetSession -ScriptBlock { & $using:CMD }
If you would like execute a bat file from another machine by using PowerShell Remote Session, simply enter dot and then follow by a whitespace, then enter the exact path of bat file located on that remote machine.
Example
Invoke-Command -ComputerName RemoteComputerName -Credential $credential -ScriptBlock {. "D:\Temp\Install_Something.bat"}

Powershell/batch uninstall script works locally but not when using invoke-command

I have a script that installs an .exe with some arguments remotely to a list of servers that works fine. When I try to do almost the exact same thing but run the uninstall.exe that gets installed to C:\Program Files (x86)\ it won't work.
When I run the scripts on the server locally, it kicks off the uninstall. When I try to run the exact same script or command using the powershell invoke-command it won't work.
$serverlist = Get-Content -Path C:\NagiosInstall\test.txt
ForEach ($server in $serverlist) {
New-Item -Path "\\$server\C$\" -Name "NagiosInstall" -Force -ItemType "directory"
Copy C:\NagiosInstall\ncpa-2.1.6.exe \\$server\C$\NagiosInstall\ncpa-2.1.6.exe
Copy C:\NagiosInstall\install.bat \\$server\C$\NagiosInstall\install.bat
invoke-command -ComputerName $server -ScriptBlock {C:\NagiosInstall\install.bat}
Start-Sleep -s 15
invoke-Command -ComputerName $server -ScriptBlock {Remove-Item -LiteralPath "C:\NagiosInstall" -Force -Recurse}
}
The install .bat is just a simple command to silently install that ncpa-2.1.6.exe.
Above is my install script, that part all works fine.
invoke-command -ComputerName $server -ScriptBlock {Start-Process -FilePath "C:\Program Files (x86)\Nagios\NCPA\uninstall.exe" -ArgumentList "/S"}
Running the above command, nothing happens. No errors, nothing.
& "C:\Program Files (x86)\Nagios\NCPA\uninstall.exe" -ArgumentList "/S"
But running the above command in powershell that's running as admin locally on the server and it works just fine.
I've also tried the same approach to create and copy and run a batch file, very similar to the above "install" code. Same thing... nothing happens but if you run the batch locally on the server, it works just fine. I can post this code if anyone is interested.
I'm guessing it has to do with the invoke-command or the fact that it's in C:\Program Files (x86) which might make the syntax different, but I've tried many things and I'm out of ideas besides making an account and posting here.
The issue is that Invoke-Command runs non-interactively, and therefore cannot run as Administrator and respond to a UAC prompt.
The only workaround is to connect to the computer via a PSSession with credentials, and execute it that way:
$Cred = Get-Credential
$Session = New-PSSession -ComputerName $server -Credential $Cred
Invoke-Command -Session $Session -ScriptBlock {Start-Process -FilePath "C:\Program Files (x86)\Nagios\NCPA\uninstall.exe" -ArgumentList "/S"}
$Session | Exit-PSSession
Edit:
The reason that the installer works is that the UAC prompt for Windows Installs is different than anything else in Windows see: How to Silence the UAC Prompt for Per-Machine MSI Packages for Non-Admins or Using Windows Installer with UAC.
Essentially, Windows Installer (already running as admin and UAC approved), is what runs the install on your behalf, and it is Windows Installer and installer settings that determines if you need to see a UAC prompt or not. Hence, this is why the install works. Windows Installer determined that you did not need to see the UAC prompt, and the install proceeds.
Uninstalling is different. Since you are running uninstall.exe, the executable needs admin access and Windows will do UAC before the uninstall.exe even runs.