Kill a process on multiple remote machines - powershell

I am looking as the title says to kill a process (for example name.exe) on multiple remote machines. I can do it individually using pskill or taskkill using (for example):
pskill -t \ -u -p name.exe
but this becomes impractical with 50+ machines.
Is there a way to make it read a text file of IP Addresses like psexec does using the #C:\name.txt or in powershell or something similar?
All devices are on the same domain.
Thank you in advance for your help.

If you have a text file with a list of machines you could do it trivially with:
get-content serverlist.txt | Foreach-object {& pskill -t \\$_ -u -p name.exe}

There are many methods to do this in Powershell like WMI, Invoke-command etc.
Here is an example to do it using WMI:
$cred = get-credential
It will pop-up for Credential. This way you can make sure that credential is not visible in the script.
(Get-Content 'c:\Temp\Computers.txt') | ForEach-Object {
Get-WmiObject -computer $_ -class win32_process -filter "name = 'name.exe'" -credential $cred| %{$_.terminate()} | out-null
}

Related

Powershell Invoke-GPUpdate - "No Logoff" possible?

Looking to run Invoke-GPUPdate -force to a group of remote computers and respond to the logoff prompt with "No".
Tried:
Echo "n" | invoke-gpupdate
Error:Invoke-gpupdate does not accept pipeline input
Command Used:
Invoke-GPUpdate -Computer $computer -RandomDelayInMinutes 0 -force
Unfortunately it looks like this cmdlet initiates/schedules a run of gpupdate that ends up happening separately (out of process), so there isn't much to do via PowerShell's standard ways of dealing with something like that, since the prompt doesn't come from within PowerShell. There's a -LogOff parameter, but it's a switch parameter which implies that its value is meant to be used just for doing the logoff. You can try it this way: -Logoff:$false but most likely it won't work to get rid of the prompt.
I think your best chance is not to use this cmdlet, but to instead use Invoke-Command with gpupdate.exe directly:
Invoke-Command -ComputerName $computer -ScriptBlock {
echo nn | gpupdate.exe /force
}
But this requires that PowerShell remoting is enabled on the machines you want to manage.

Can I RDP through mstsc and run a script on that remote desktop?

I'm writing a script which needs to RDP to a few servers, do processes there and then come back.
mstsc /v:<computer> by itself looks great as it's security/credential prompt is the same as if you manually executed it.
However, after some research it appears that's meant to be a command line utility and nothing more because trying things like:
mstsc /v:104.209.198.181 | Invoke-Command -ScriptBlock {"New-Item C:\Users\<me>\Desktop\Success.txt -ItemType file"}
doesn't work.
So I tried Enter-PSSession <computer> -Credential $env:UserName which people use but it looks like a mess to deal with compared to mstsc because it looks primitive (an article I read yesterday tried to say this type of prompt is ALWAYS a phishing scam which obviously it's not but try telling management), it doesn't auto-populate domains, and I get a WinRM error which I'm sure will be a rabbit hole.
So is it possible to RDP with mstsc and then pipe commands to it so they're executed on that computer?
The answer is no. You cannot initiate some kind of pipe using MSTSC.exe.
You can, however, use PSRemoting to send the command like you're trying to do already:
Invoke-Command -ComputerName '<FQDN>' -ScriptBlock {
New-Item -Path "$HOME\Desktop\Success.txt" -ItemType File
}
If you don't know the FQDN, then look up the IP using DNS:
[System.Net.Dns]::GetHostEntry('104.209.198.181')
All this failing.. you can fall back on WMI, but you don't get any console feedback:
$WmiArgs = #{
'Class' = 'Win32_Process'
'Name' = 'Create'
'ArgumentList' = 'powershell -NoProfile -NonInteractive -WindowStyle Hidden -Command "New-Item -Path $HOME\Desktop\Success.txt -ItemType File"'
'ComputerName' = '104.209.198.181'
}
Invoke-WmiMethod #WmiArgs
While I tested the above is working, you can shorthand even this!
([wmiclass]'\\104.209.198.181\root\cimv2:win32_process').
Create('powershell -NoP -NonI -W Hidden -C "New-Item -Path $HOME\Desktop\Success.txt -ItemType File"')
With this method, however, you cannot pass credentials.

Run a powershell script from one computer to the next

I already have code written to connect to another computer in my house and pull music files from the C drive. However, I am trying to find out how to keep this code, but modify it in a way that I can use it to run code on the second computer, then save it to a text file.
foreach ($server in Get-Content .\serverList.txt){
psexec \\$server -u username-p password cmd /c dir c:\*.mp3 /s > c:\Powershell\$server.txt
}
You could write a book on PowerShell Remoting (several people have) but it's reasonably straightforward.
On both computers run Enable-PSRemoting to configure all the settings. Then on the originating computer (the one making the remote call) run Set-Item WSMan:\localhost\Client\TrustedHosts -Value '*' (if you are security conscious replace the * with the IP of the remote PC).
Then you can run the all-powerful Invoke-Command to do all sorts of awesome stuff remotely. Unless you're on a domain or there's an identical user on the remote PC you'll need to provide credentials which means either prompting for them or saving them, but if I go into too much detail we'll both be here all day. Pretty easy to find the answers on Google.
$cred = Get-Credential
foreach ($server in Get-Content .\serverList.txt) {
Invoke-Command $server -Credential $cred -ScriptBlock { Get-ChildItem C:\*.mp3 -Recurse } | Out-File C:\Powershell\$server.txt
}

Powershell: waiting for changed directory

To make it short, I want to connect to a server that is running Virtual Machines and then get a List of all installed machines, the command I use for this is:
Invoke-Command -ScriptBlock {enter-pssession -ComputerName <name>}; Invoke-Command -ScriptBlock {Get-VM} | select-Object -Property name
This line contains two commands at first:
Invoke-Command -ScriptBlock {enter-pssession -ComputerName <name>};
this part connects to the server, and then:
Invoke-Command -ScriptBlock {Get-VM} | select-Object -Property name
This command gets a list of the VMs currently on the server and returns specific properties of these servers.
However, because the connection needs a short time until it is set up, the "get-vm" command is still set in the previous direction and results in an error report.
I want to know if there is a way to wait for ether a command to be finished or for a change in the directory, without having an extra loop running for this time, or waiting for a hard set time.
I don't know why are you trying to do what you are trying to do, what you should do is:
Invoke-Command -SessionName (or -ComputerName) -ScriptBlock {Get-VM | Select-Object -Property name}

Determine PowerShell version remotely via WMI

I have searched here and elsewhere and could not find an answer, so here is my question.
What is the best way to determine PowerShell version on a remote computer using WMI?
Background
My task is to audit and update some 1000 servers to recent version of PowerShell. Some of them have PowerShell v1 and some do not have WinRM configured, so Invoke-command is not an option. PSExec is also not an option in this environment. This is why I need to use WMI for this task.
Any help would be appreciated.
EDIT:
After much research I'm still leaning towards WMI. In particular retrieving the file version of "powershell.exe". This seems to me to be the only way to cover all versions.
Code I have so far is here:
$path = "C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe"
$query = "SELECT Version FROM CIM_DataFile WHERE Name = '$path'"
$PSFileVer = Get-WmiObject -Query $query -ComputerName $servername -Credential $creds
$BuildVer = [version]$PSFileVer.Version.Split()[0]
All I need now is a comprehensive list, mapping file version (build number) to powershell version. Any Ideas?
The solution from here is
$command = "ipconfig/all > C:\temp\result.txt"
$cmd = "cmd /c $command"
Invoke-WmiMethod -class Win32_process -name Create -ArgumentList $cmd -ComputerName "remotepc"
sleep 1
Get-Content \\remotepc\C$\temp\result.txt
You can also do similar via this method. If you do so, you can't get the return value directly, u must redirect to a file.
You could setup share for the results instead of putting result on local machine
If it helps here is the command :
$command = "powershell -command "+'"$PSVersionTable.PsVersion.Major | out-file c:\temp\version.txt"'