4 ms·
I had an opportunity to use PowerShell recently. The task was simple: on a bunch of freshly installed windows 8 boxes, kill a running graphical program of a ce
by felixgallo 11y ago
I had an opportunity to use PowerShell recently. The task was simple: on a bunch of freshly installed windows 8 boxes, kill a running graphical program of a certain name, copy over new executables, and restart that graphical program. The kind of thing you do essentially constantly on Unix boxes.
I urge anyone at all with any interest in PowerShell to give it a shot. Spoiler: it's not possible without an epic level of hackery; but along the way, you will uncover that PS uses the same parameter to mean very different things for different commands, that the 'everything is an object' conceit doesn't work when the object you want doesn't exist, that PS is chock full of hacky, revolting cruft already despite its youth, hacky revolting cruft that makes oh-my-zsh look like /bin/rc, that most windows commands will fill your screen with banner(8) style output even on success, and that no two windows commands are alike.
Given which decade it was developed in, PowerShell represents the most absolute and fundamental failure of software I've had the pleasure of encountering in the last five years; and I've seen Windows 8.0. Anyone who thinks PowerShell is at all any good has, axiomatically, never seen any other shell besides cmd.exe before. You may think I'm exaggerating. Please, try the example above, then report back here with a list of what you had to do.
- shadowfox 11y ago> Anyone who thinks PowerShell is at all any good has, axiomatically, never seen any other shell besides cmd.exe before. You may think I'm exaggerating Really. That feels like quite an uncharitable statement. The only reason someone could think something that you don't like is good because they just don't know any better?
- useerup 11y agoUsing 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
- useerup 11y ago> you will uncover that PS uses the same parameter to mean very different things for different commands Example needed. The claim is surprising, given that there exists a PowerShell Command Line Standard which includes a list of parameter names and their semantics: https://technet.microsoft.com/en-us/library/ee156811.aspx#EMAA https://technet.microsoft.com/en-us/library/ee156811.aspx#EM...