Need to unblock remote ps script run using psexec - powershell

As part of our automatic build and deploy using TFS, I need to execute a powershell script on a target server. The following is the (simplified for clarity) command run on the build server by the TFS Build Agent PreBuild step, in the (pre-build.ps1) script...
C:\Builds\<snip>\psexec.exe -accepteula -s -i \\WSRMO632WEB powershell.exe \\TFS-BAGENT-POC\<snip>\PreBuild-AppPool.ps1 -name AppPool-DEV -usr User -pw pass
If I run the powershell part of the command on the WSRMO632WEB box in a command window, I get the warning...
Security warning
Run only scripts that you trust. While scripts from the internet can be useful,
this script can potentially harm your computer. If you trust this script,
use the Unblock-File cmdlet to allow the script to run without this warning message.
Do you want to run \\TFS-BAGENT-POC\<snip>\PreBuild-AppPool.ps1?
[D] Do not run [R] Run once [S] Suspend [?] Help (default is "D"):
If I choose R, the script runs and performs correctly.
My problem is that I cannot get the syntax correct to incorporate the Unblock-File cmdlet.
I'm currently thinking that I'm going to have to use multiple psexec commands, one to copy the file from the build server, one to unblock it and a third to finally run it.
Surely it should be easier than that, but I can't find a suitable example and can't get the syntax right.
Any suggestions, please?

You can use Powershell's -command to first do an Unblock-File, then run it as a script.
C:\Builds\<snip>\psexec.exe -accepteula -s -i \\WSRMO632WEB powershell.exe "-command \"$file='\\TFS-BAGENT-POC\<snip>\PreBuild-AppPool.ps1'; $file; Unblock-File $file; & $file\"" -name AppPool-DEV -usr User -pw pass
Quotes are necessary so that the full command string will be passed to Powershell. Add backslashes to escape themselves as necessary.
UPDATE: You can also try feeding the required command into standard input.
echo r | C:\Builds\<snip>\psexec.exe -accepteula -s -i \\WSRMO632WEB powershell.exe \\TFS-BAGENT-POC\<snip>\PreBuild-AppPool.ps1 -name AppPool-DEV -usr User -pw pass
This way Powershell will run, get the "R" for "Run once" and run the script, without any changes to the script or calling command.

Related

Is there a way to execute powershell commands remotely on a domain user from the DC?

Let's say for example, I have a domain controller and a client that is joined to the domain.
If I wanted to remotely lock out the client I would supposedly run
Invoke-Command -ComputerName [workstation name] -ScriptBlock {rundll32.exe user32.dll, LockWorkStation}
However this does not work. I'm assuming this is because the Invoke-Command cmdlet runs the code in the scriptblock but returns anything back to the local terminal. What I'm trying to accomplish is to have the code or powershell script run locally on the remote computer.
My question is first of all if this is the correct approach and second why the command I'm running does not work.
Download PsExec from https://learn.microsoft.com/en-us/sysinternals/downloads/psexec and run following command.& "C:\PSTools\PsExec.exe" -s -i \\COMPNAME rundll32.exe user32.dll,LockWorkStation
As per my comment when using PSExec... So, stuff like this ---
PsExec.exe \\ -d -u \Administrator -i cmd.exe /c "C:\windows\system32\rundll32.exe user32.dll, LockWorkStation"
Or using PowerShell with quer.exe ...
(it's a tool in every modern Windows version)
quser | Microsoft Docs
...in a PowerShell remoting script, like described here:
How To Log Off Windows Users Remotely With PowerShell
Again the work is being done by quser.exe, not PowerShell specifically. PowerShell is just being used to run quser.exe remotely. You could do the same, by copying PSExec to the remote host and do a similar operation.

psexec trying to exec script error

I am learning how to interact with PowerShell and PsTools, and I have a problem with psexec.
I got a ps1 script named test.ps1 and inside it I have Get-Service which gives me the all services in my computer. Now I am going into PowerShell and go to c:\pstools. Then I type
psexec.exe C:\test\test.ps1
and it fails and returns me this error:
%1 is not a valid Win32 application
What could be the problem?
PsExec launches an executable. You need to specify the executable for PowerShell and associated arguments:
psexec.exe -accepteula -nobanner -s -h -d powershell.exe -ExecutionPolicy Bypass -NoProfile -NoLogo -File "C:\test\test.ps1"
The immediate answer to your question is:
psexec requires a (binary) executable as its first argument and cannot execute scripts directly.
Therefore, you must pass the Windows PowerShell executable name to psexec and in turn pass the desired script to the latter as an argument, via the -File parameter:
psexec powershell -File C:\test\test.ps1
That said, this particular use of psexec is pointless, as it would execute the script locally, as the current user, in which case use of psexec is a needless complication:
If you already know that, and the psexec command at hand is just a simplified example, never mind.
Otherwise, read on below.
The ps in psexec and PsTools has nothing to with PowerShell; PsTools is a collection of CLIs for managing Windows machines remotely, including processes, a common abbreviation of which is "ps", inspired by the standard ps Unix utility, which in turn inspired the initial tool in the collection, pslist; the primary purpose of psexec is to invoke arbitrary command lines on remote machines[1]
.
To invoke a PowerShell script locally:
From inside PowerShell itself, simply invoke the file path directly:
PS> c:\test\test.ps1
PS> & "c:\test\test.ps1", if the file path is / must be quoted or is provided via a variable or expression.
From outside of PowerShell, such as cmd.exe ("Command Prompt") or bash, you must invoke the PowerShell executable explicitly and pass it the script file path via the -File parameter:
Windows PowerShell: C:\> powershell -file c:\test\test.ps1
PowerShell Core: C:\> pwsh -file c:\test\test.ps1
In other words: the PowerShell's executable name is
powershell.exe for Windows PowerShell,
vs. pwsh for the cross-platform PowerShell Core edition (with extension .exe on Windows).
If you do need remote execution:
Pass \\-prefixed machine name(s) or IP address(es) to psexec; e.g., the following command executes the hostname utility on machine somemachine:
psexec \\somemachine hostname
There is no benefit to using psexec without targeting a different machine.[1]
However, psexec is normally not needed, because PowerShell has built-in support for remoting (i.e., the ability to execute commands on other machines; remoting requires setup, however - run Get-Help about_Remote_FAQ for more information); e.g., the equivalent of the above command is:
Invoke-Command -ComputerName somemachine { hostname }
[1] As TheIncorrigible1 points out, psexec can also be used for local execution as the system account (NT AUTHORITY\SYSTEM, the account that represents the computer as a whole) with the -s option.
Additionally, you can also run locally as another user, using the -u parameter - which, however, the standard runas utility can do as well (the latter doesn't offer passing the target user's password as a parameter for security reasons, but does offer to securely save a password for later reuse).
Run psexec -h for help.

How to continue executing a Powershell script after starting a web server?

I have a script which calls two other scripts.
script0.ps1
Invoke-Expression C:\script1.ps1
Invoke-Expression C:\script2.ps1
The first script starts a web server:
script1.ps1
./activate anaconda_env
cd C:\webserver
python api_server.py
The second script starts a ngrok service:
script2.ps1
./activate anaconda_env
cd c:\ngrok
./ngrok -subdomain=mysd 8000
The problem is that the script0.ps1 only executes script1.ps1. At this point the web server starts running in the console and so the second command of script0.ps1 is not executed.
How to make write the scripts so both commands are executed? Or, how to write just one script to execute all commands but in two separate consoles?
The final result should be:
1) a web server running in a console with activated anaconda environment
2) a ngrok service running in a console with with activated anaconda environment
Change Script1.ps1 to launch python as a job:
./activate anaconda_env
cd C:\webserver
Invoke-Command -ScriptBlock {.\python.exe api_server.py} -AsJob -ComputerName .
I don't have the specific script you're using, so I tested this with turtle.py which ships with 3.43 and it seems to work.
You don't need to use Invoke-Expression to run a Powershell script from another script. Just run it as if you're on the command line
c:\script1.ps1
c:\script2.ps1
Now if script1.ps1 starts a process that doesn't exit, it will halt execution for the next statements in the script, and thus also prevent the second script from running.
In most cases this sequential execution is exactly what you want.
In your case you can start the scripts asynchronously by using Start-Process.
So your main script becomes something like:
start-process c:\script1.ps1
start-process c:\script2.ps1
Start-Process basically starts a new command shell to run the statement in. Check out the docs for more info. There's a bunch of parameters you can use to tweak how this happens.
To not have invoke-expression close your script you can pipe the output to Out-Null. Your code above would look like:
Invoke-Expression C:\script1.ps1 | Out-Null
Invoke-Expression C:\script2.ps1 | Out-Null

Batch files, Powershell Scripts, PSExec and System user

I'm trying to put in place some monitoring for Windows Task Scheduler, I have a Powershell script that runs the following:
$serverName = hostname
$schedule = new-object -com("Schedule.Service")
$schedule.connect($serverName)
$tasks = $schedule.getfolder("\").gettasks(0)
$tasks |select name, lasttaskresult, lastruntime
This returns a list of scheduled tasks on the server it is run on, the last task result and last run time. The purpose for this is to return a dataset to our monitoring solution (Geneos) which we can use for alerting.
We have a large Win2008 estate, so I want the script centralised allowing any of the Geneos probes to call it and return a dataset for their host. To do this I wrapped the powershell in a .bat file which does the following:
\\fileserverhk\psexec.exe -accepteula -u admin -p "pwd" powershell.exe cpi \\fileserverhk\scripts\TaskSchedulerMonitor.ps1 -Destination C:\Monitor\TaskSchedulerMonitor.ps1
\\fileserverhk\psexec.exe -accepteula -u admin -p "pwd" powershell.exe -ExecutionPolicy Bypass -File C:\Monitor\TaskSchedulerMonitor.ps1
The First step copies the .ps1 file locally to get around Powershell not trusting UNC paths and the second part runs the script.
If I run the .bat file manually from a test server it executes fine (this is logged in under an admin account). However, when I fire the .bat file via Geneos (which runs under the SYSTEM account) I get:
Access is denied.
PsExec could not start powershell.exe:
So basically my question is, how do I get PsExec to switch user when it is run under the SYSTEM account? Even though PsExec has the credentials set for another account, there is obviously something preventing it from changing when run under system.
I read to try running it with the -h switch but I get the below error:
The handle is invalid.
Connecting to local system...
Starting PsExec service on local system...
Connecting with PsExec service on <server>...
Starting powershell.exe on <server>...
Error communicating with PsExec service on <server>:
In addition to the above error, I end up with the PSExec and powershell processes hung on the remote machine. The interesting part is I can see the PSExec and PSEXEC.SVC running under SYSTEM and the powershell running under admin, so it's almost there, but something isn't quite right there.
We managed to get there using a powershell wrapper on the Windows schtasks command (link here). Schtasks can be run under the SYSTEM account and will return all the necessary task information, so we no longer needed to faff about with permissions, and no more clear text passwords on the environment (bonus).
We wrapped:
schtasks.exe Query /FO CSV
in a powershell script, and used PS to format the output into the csv style expected by Geneos.

Run PowerShell scripts on remote PC

I have installed PS 1.0 on a remote PC(RPC001). I used Windows Sysinternals
tool PSExec.exe to execute the following process on the remote:
PSExec \\RPC001 -u myID -p myPWD PowerShell C:\script\StartPS.ps1 par1 par2
I can see the PowerShell.exe process running on the remote PC afterwards, but it is actually doing nothing, just hanging there. I tried to put a simple code of "Write-Output/Host" a string in the script. I run the same script on the remote by RTS, it works there.
Not sure if I miss anything else to run the script by using PSExec, or it is PSExec.exe limitation. I would like to start a PS script on remote to do something there locally (compress some files locally and remove old files) from my box.
I asked a similar question in Stackoverflow: Run remote process by powershell. Don suggested me to use PSExec. It sounds like an alternative way to solve the issue. However, I cannot get it working with PowerShell. Any way to get PS working on remote PC?
By the way, I cannot use PS 2.0 since my network does not allow me to install Windows XP SP3, which is required for PS 2.0.
The accepted answer didn't work for me but the following did:
>PsExec.exe \\<SERVER FQDN> -u <DOMAIN\USER> -p <PASSWORD> /accepteula cmd
/c "powershell -noninteractive -command gci c:\"
Example from here
After further investigating on PSExec tool, I think I got the answer. I need to add -i option to tell PSExec to launch process on remote in interactive mode:
PSExec \\RPC001 -i -u myID -p myPWD PowerShell C:\script\StartPS.ps1 par1 par2
Without -i, powershell.exe is running on the remote in waiting mode. Interesting point is that if I run a simple bat (without PS in bat), it works fine. Maybe this is something special for PS case? Welcome comments and explanations.
Can you try the following?
psexec \\server cmd /c "echo . | powershell script.ps1"
Accepted answer doesn't work for me, but this does. Ensure script in the location (c:\temp_ below on each remote server. servers.txt contains a list of IP addresses (one per line).
psexec #servers.txt -u <username> cmd /c "powershell -noninteractive -file C:\temp\script.ps1"