4 ms·
Using the non-aliased verbose form of the cmdlets: $hosts = 'host1','host2','host3' $source = '\\host0\c$\source' $dest = 'c:\dest' $executable
by useerup 11y ago
Using the non-aliased verbose form of the cmdlets:
$hosts = 'host1','host2','host3'
$source = '\\host0\c$\source'
$dest = 'c:\dest'
$executable = 'C:\Program Files (x86)\Notepad++\notepad++.exe'
Invoke-Command -Computer $hosts -ScriptBlock {
Get-Process | Where-Object Path -eq $using:executable | Stop-Process -Force
Copy-Item -Path $using:source -Destination $using:dest
}
Explanation:
Line 1-4: Set up variables to make the script more explanatory. Line 1 defines an array (the "," operator)
Line 6: Invoke-Command takes an array of (remote) hosts (the -Computer parameter) to execute the script block (the -ScriptBlock parameter).
Lines 7-9: The script to execute at each host simultaneously (the Invoke-Command executes the scripts in parallel at each host)
Line 7: Get the process list (Get-Process), pipe through the filter (Where-Object) which selects only the process(es) executing the desired executable, pipe those processes to the Stop-Process cmdlet which will forcably stop the process.
Line 8: Copy files from the desired source at an UNC path to the local machine at the destination
Now, the above script was the canonical way, using the long form. For casual scription, I could have written just this:
$hosts = 'host1','host2','host3'
$executable = 'C:\Program Files (x86)\Notepad++\notepad++.exe'
icm $hosts { ps | ? Path -eq $using:executable | kill -f; cp \\host0\c$\source c:\dest }
- warfangle 11y agoWhile likely to work (I don't use powershell), I think you missed the main constraint posed: kill a running GUI with a certain name. Your solution finds the process to kill only if the executable path is at a known location. How would you do this if you only know what the process name will be -- e.g., what if the executable path is on D:\stuff\gui.exe on host1 and E:\secretstuff\gui.exe on host2, if gui.exe always runs as a process named "Updatable GUI Thing"?
- useerup 11y agoSilly me, I assumed that the executable path was the requirement. My bad. If you need to find a process just by it's name, it is even simpler: Just indicate the process name (possibly with wildcards) to Get-Process (alias ps): ps Notepad++ | kill Actually, kill (alias for Stop-Process) takes a name parameter directly, so the "kill" line from the script could be written as simply kill notepad++ But your question is actually really good, because what if we did not know the neither the process name nor the executable, but -say- only the Window title? Get-process (alias ps) will produce a sequence objects describing the running processes. If I want to know what properties those objects have that I can possibly filter on, I can pipe the objects through the Get-Member cmdlet (alias gm): ps | gm This produces a table-formatted list like this (shortened): TypeName: System.Diagnostics.Process Name MemberType Definition ---- ---------- ---------- Handles AliasProperty Handles = Handlecount Name AliasProperty Name = ProcessName ... MainModule Property System.Diagnostics.ProcessModule MainModule {get;} MainWindowHandle Property System.IntPtr MainWindowHandle {get;} MainWindowTitle Property string MainWindowTitle {get;} MaxWorkingSet Property System.IntPtr MaxWorkingSet {get;set;} ... Site Property System.ComponentModel.ISite Site {get;set;} StandardError Property System.IO.StreamReader StandardError {get;} StandardInput Property System.IO.StreamWriter StandardInput {get;} StandardOutput Property System.IO.StreamReader StandardOutput {get;} StartInfo Property System.Diagnostics.ProcessStartInfo StartInfo {get;set;} ... Product ScriptProperty System.Object Product {get=$this.Mainmodule.FileVersionInfo.ProductName;} ProductVersion ScriptProperty System.Object ProductVersion {get=$this.Mainmodule.FileVersionInfo.ProductVersion;} Lo and behold, there is a property called MainWindowTitle. So to stop a process by it's main window title I could write: ps | ? MainWindowTitle -eq 'Deepthought Main Console' | kill That is, find all processes, pipe them through a filter selecting only those where the MainWindowTitle equals the desired text, and pipe those processes to the Stop-Process cmdlet
- felixgallo 11y agohey, this was a pretty good try! But here's what else you need to do: https://rkeithhill.wordpress.com/2009/05/02/powershell-v2-remoting-on-workgroup-joined-computers-%E2%80%93-yes-it-can-be-done/ https://rkeithhill.wordpress.com/2009/05/02/powershell-v2-re... and if that's not hair-raisingly terrifying enough (note the super-intuitive 'set-item wsman://...' call), you'll quickly find that when you start a program (which you left off) using a script remotely, it doesn't show up anywhere on-screen, despite being authenticated as the logged-in user, but it does show up in the process list. Guess why THAT is. There are some pretty parts to PS; but they fall apart, at the touch, instantly, like fairy buildings made of dew.
- useerup 11y ago> hey, this was a pretty good try! But here's what else you need to do: No I don't. To open up a machine for remote administration, all I have to do is run Enable-PSRemoting like so: Enable-PSRemoting -Force For domain-joined machines the authentication from there is just automatic, -i.e. when I use Invoke-Command it automatically created an authenticated and encrypted connection for the duration of the script execution. > you'll quickly find that when you start a program (which you left off) using a script remotely, it doesn't show up anywhere on-screen, despite being authenticated as the logged-in user, but it does show up in the process list. Guess why THAT is. That has nothing to do with PowerShell and everything to do with your expectation that you have equally poor session separation as with your typical nix. With sufficient rights you can of course stop any process. But to reach in and control another user session is something else. On Windows, processes are separated not just by the account they run under, but also by the session* under which they are created. Security barriers prevents a process in one session from interacting with processes in another session, even if they run as the same user. This security boundary was raised to prevent compromised user processes from reaching into services and vice versa. This is part of the protection against shatter attacks and more. I know a utility like psexec (sysinternals) may be able to launch a process in a foreign session, but I'm honestly not sure how it achieves this without some kernel support. > but it does show up in the process list. Guess why THAT is. That is because when you launch a process is launches in your session. A session is associated with a Windows Desktop (an operating system object type) which is a namespace separation somewhat like cnames in Linux. Windows on your (remote) session lives on the non-visible desktop associated with that session. When you log off it destroys the session and any processes running under the session. You may not agree with the extra security features built into Windows, but the separation they create has noting to do with PowerShell.