This question already exists:
Power shell Script execution from the AD on the all domain joined machines
Closed 6 years ago.
I have written a very short power shell script, that will download and install the ossec agent's binaries from locally hosted HTTP server and execute it on the respective machines. The binaries are named with respective machines IP address. I want to execute this script on more than 500 hundred machines from my active directory as a start up script but it is not working.
I have tested the script directory from power shell on 5-6 machines and it is working. Can some one please review what am doing wrong ? Here is the simple powershell script.
$user=$env:username
$localIpAddress=((ipconfig | findstr [0-9].\.)[0]).Split()[-1]
powershell -Command "(New-Object Net.WebClient).DownloadFile('http://192.168.10.220/$localIpAddress.exe','C:\Users\$user\Downloads\ossec.exe')"
cd "C:\Users\$user\Downloads"
.\ossec.exe /S
I'd check your ExecutionPolicy settings and possibly see if the file needs "unblocking" - see here for more info.
On a different note, using WMI is a slightly cleaner way of getting your machine's IP address, e.g.:
[String] $strIP = (Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter 'IPEnabled = "true"' | Select-Object -First 1).IPAddress;
Related
I have followed the advice here and here to write a PowerShell script that remotely kills a process:
Get-WmiObject Win32_Process -Filter "Name='myapp.exe'" -ComputerName remotecomputername | Invoke-WmiMethod -Name Terminate
The above works when I execute it on my machine, but when it's run remotely, targeting my machine by a user setup as per the instructions on the second link, the command fails silently. Any advice on what's wrong / how I can debug this?
As described here:
Generally speaking, any operation that WMI can perform on the local
computer can also be performed on a remote computer where you have
local administrator privileges
Once I setup a user with admin privileges to use WMI on my computer they can execute the script remotely without passing credentials.
So, I'm writing tools in PowerShell to execute files on remote computers. I was initially using PSexec but switched them to .net framework using win32_process. When I ran an install file on the remote machine using win32_process, it failed. And after trying gwmi win32_process on the remote machine, that failed. So accessing the wmi objects is probably the problem. Anyway! I ended up using PSexec and it succeeded, and i verified that it did. But, that got me thinking about how PSexec connects to the remote machine, and I was wondering if anyone on here knew either how I could look at PSexec source code or if someone flat out knew how it connects and executes.
I couldn't find anything on it online, just a bunch of articles about what it can do. Maybe I just suck at researching though.
I have done this using the Invoke-WmiMethod cmdlet against remote machines. You need to include any switches in your executable path but the below code sample should get you there assuming you have appropriate permissions on the local / remote hosts.
See https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/invoke-wmimethod?view=powershell-5.1 for more details on the cmdlet.
#local path on the remote machine that will be run including any switches needed
$exePath = "c:\mypath\myfile.exe -s -norestart"
# Use FQDN or IP if netbios name is not reachable
$server = "myserver"
try {
Invoke-WmiMethod -ComputerName $server -Class win32_process -Name create -ArgumentList $exePath -ErrorAction Stop | Out-Null
}
catch {
Write-Host "Failed to execute program on $server. Error Details: $_.Exception.Message" -ForegroundColor Red
}
I can't speak to how PSExec works for you to compare but this method has worked for me in the past executing applications on remote hosts using only native PowerShell.
How can I get a remotely executed script to know it's own location? I'm using Invoke-Command to run a script on a remote server. The script needs to create files in the directory in which it lives. Running with relative addressing doesn't work (i.e. .\output.log), the scripts generally end up in my user profile on the remote server. I tried all the methods outlined in this question but none of them seem to work when the script is remote.
Update: Provided script invocation code per request
$server='ad1hfdahp802'
$remotepath='\\ad1hfdahp802\d$\AHP\pi_exceed_presentation\pi_exceed_presentation_deploy.ps1'
$SDFEnvironment='INT'
Invoke-Command -ComputerName $server -FilePath $remotepath -ArgumentList($SDFEnvironment,$remotepath)
The remote script takes the $remotepath and turns it into a file system path.
Using -FilePath with Invoke-Command means that you read the script locally and send the content as the scriptblock to the remote computer. $PSScriptRoot only works when the script is executed directly on the target. You could try using:
Invoke-Command - ComputerName "computer1" -Scriptblock { & '\\server\path\to\script.ps1' } -Authentication Credssp
Be aware that you need CredSSP to make this work since the remote computer can't use your credentials to access network-resources without it. As an alternative, you could use psexec (or start a process remotely). Ex.
psexec \\computer1 powershell -noprofile -file \\server\path\to\script.ps1
After trying some of the changes proposed I've come to understand that the Invoke-Command isn't actually running the remote script at its original location, but rather loading it from the original location and then running it under the context of PowerShell as the user running the local script. The "script directory" is actually a directory in the user's workspace regardless of where the script originally lived.
This clarifies things for me somewhat. While there may be ways to divine where the script originally came from or to actually start a session on the remote server then run the script as a "local" script there, the need for the remote script to further access other servers, creating multiple hops in authentication, means I have to add CredSSP to the mix.
It seems my original plan, to pass the path I'm using to locate the script to the script so it can place output files in the original directory, is probably the best approach given that I also have to add CredSSP to the mix.
I'm open to refutation, but I don't think any of the proposed solutions actually improve the functionality of the remote script so I'm going to stick with what I started with for now. Thanks to everyone for their contributions.
Enter a session on the remote server, and call the script from there.
local PS> Enter-PSSession -ComputerName $server ...
remote PS> powershell d:\AHP\...\script.ps1
remote PS> exit
local PS>
Then you can use $PSScriptRoot in the script in the remote server to get the local path of the directory of the script on the remote server.
EDIT:
To locate the script on the remote server, you can use your knowledge of the network path of the script file, and parse the output of net share to map network path to local path on the remote server.
remote PS> net share | where { $_.StartsWith('D$ ') } | foreach { [regex]::Split($_, " +")[1]}
This is incredibly difficult to do. I can't believe it. It should be so easy.
Anyway, using WMI (with both vbscript and perl) I'm able to start a process on a remote machine that runs a .exe, but I cannot get the output to write to a log. This is driving me nuts. I have to use WMI or powershell because I can't install anything additional on the remote machines, which are all Windows 2003 or newer. I also cannot assume that powershell remoting is enabled on all target machines, so I may not even be able to use powershell. This can cause a problem with powershell.
Here is what I'm trying to do in psuedo code:
servers = server1, server2, server3
for each server in servers
run command on remote server >> log.txt
next
I'm assuming you have powershell remoting enabled on all the servers and that you want the results saved in a local log file (ie not on each server)...
$Servers = "server1", "server2","server3"
Invoke-Command -ComputerName $Servers -ScriptBlock { ping.exe www.stackoverflow.com } >> c:\localfile.txt
This also assumes that your exe outputs to stdout, I think there will be issues capturing other streams.
Just listened to Hansellminutes podcast. He had a talk with two Microsoft PS developers. They mentioned PS V2 remoting features.
I have some scripts based on PS v1. In terms of remoting commands or executions, I installed PS on local and a remote machines. Then I use PsExec.exe to push bat on remote to execute PS scripts. Now I am thinking to take advantage of PS V2.
To simple questions I have, to get a list of files on local, I can use the following codes:
$fs = Get-Item -Path $Path | Where { !$_.PSIsContainer ... } # more constrains in ...
if ( $fs -ne $null )
{
# continue to work on each file in the collection
...
}
What is the equivalent command to get a collection of files from a remote? I prefer to get a similar collection of file objects back so that I can access to their properties.
The second question is how to exec a command on remote with external application? I tried to use WIM Process before, but I could not get WMI class working on a case of Windows 2008 server. Then I used PsExec.exe to push a bat to a remote to execute PS script. It works in the cases. However, the problem I have to install PS on the remote as well. I am going to working another remote. I'll try to avoid to install PS on the remote. Can I take PS V2 advantage to execute a command on a remote Windows? What's the new commands?
By the way, normally, I have to pass user name and pwd to a remote. I guess in PS I have to pass user/pwd as well.
You can either put your code above in a script file and invoke it on a remote computer using V2 remoting like so:
PS> Invoke-Command remotePCName -file c:\myscript.ps1
You will need to be running with admin privs (elevated if UAC enabled) in order to use remoting. The command above will copy the script to the remote machine, execute it and return deserialized objects. These objects are essentially property bags. They are not "live" objects and setting properties on them like IsReadOnly will not affect the remote file. If you want to set properties then do it in your script that executes on the remote PC.
The option if you have a little bit of script is to use a scriptblock like so:
PS> Invoke-Command remotePCName { Get-Item C:\*.txt | Where {$_.IsReadOnly }
You can execute native commands (EXE) on the remote computer in either script or a scriptblock. You only need to make sure the EXE is available on the remote PC.
Regarding credentials, if you're on a domain and you have admin privs on the remote computer you won't need to pass credentials as your default credentials should work. If you need to run as a specific user then use the -Credential parameter on Invoke-Command like so:
PS> $cred = Get-Credential
PS> icm remotePCName { gci c:\windows\system32 -r *.sys } -credential $cred
Regarding your last comment, no PowerShell will use Windows integrated security so you should not have to pass any username or password unless you wanted to run it as a different user.
If you haven't yet enabled PS remoting, every time I've tried I've had to actually turn off UAC while I was enabling remoting (then I could re-enable UAC once remoting was enabled). Running Enable-PSRemoting from an elevated command prompt was not enough and the error message was not at all useful.
EDIT: I've just confirmed in a fresh Windows 7 VM that this is not an issue. It could have been a beta issue that I am no longer experiencing as I've been using beta/rc/ctp of PowerShell and Windows 7 for a long time.