Powershell Kill all processes except system - powershell

In powershell, I would like to kill all processes for all users, except explorer and processes used by the system
This is where I am including the errors that are given:
$Cred = Get-Credential;
Invoke-Command -ComputerName localhost -Credential $Cred -ScriptBlock { Get-Process $env:ALLUSERSPROFILE | Where-Object -FilterScript {$_.Name -ne "SYSTEM, NETWORK SERVICE, LOCAL SERVICE"} | Where-Object -filterscript {$_.Name -ne "explorer"} | Stop-Process -WhatIf }
Cannot find a process with the name "C:\ProgramData". Verify the process name and call the cmdlet again.
+ CategoryInfo : ObjectNotFound: (C:\ProgramData:String) [Get-Process], ProcessCommandException
+ FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
+ PSComputerName : localhost

Here, this should work for you.
Function Stop-UserProcesses{
Param([string]$Computer = "localhost")
$Cred = Get-Credential
Invoke-Command -ComputerName $Computer -Credential $Cred -ScriptBlock {
Get-Process -IncludeUserName | Where{!($_.UserName -match "NT AUTHORITY\\(?:SYSTEM|(?:LOCAL|NETWORK) SERVICE)") -and !($_.ProcessName -eq "explorer")}|Stop-Process -WhatIf
}
}
Once you are convinced that it is functional remove the -WhatIf. Then just call it as Stop-UserProcesses to end everything locally, or Stop-UserProcesses SomeComputer01 to end everything on a remote system (assuming you have remote sessions enabled in your environment).
Edit: Well then, evidently the -IncludeUserName switch is new in v4. So, in order to do what you want we have to jump through hoops and use Get-WMIObject on the win32_process class, then execute the GetOwner() method for each process. Probably want to filter it so we don't end up with things like Idle throwing errors when they don't have an owner, so we'll make sure that the CommandLine property exists.
Function Stop-UserProcesses{
Param([string]$Computer = "localhost")
$Cred = Get-Credential
Invoke-Command -ComputerName $Computer -Credential $Cred -ScriptBlock {
#Get all processes
$Processes = get-wmiobject win32_process|Where{![string]::IsNullOrEmpty($_.commandline)}|Select *,#{l='Owner';e={$_.getowner().user}}
#Filter out System and service processes
$Processes = $Processes | Where { !($_.Owner -match "(?:SYSTEM|(?:LOCAL|NETWORK) SERVICE)") }
#Get processes and filter on the Process ID and name = explorer, then pipe to stop-process
Get-Process | Where { $Processes.ProcessID -contains $_.id -and $_.name -ne "explorer" } | Stop-Process -WhatIf
}
}

Related

Connect remote server and execute script

I'm trying to connect a remote server and stop a process on it using this PowerShell command
Invoke-Command -ComputerName \\srvwebui3 -ScriptBlock {
Get-Process | Where-Object {
$_.Path -like "\\abd\net$\abd\versions\Bin\HttpServer.exe"
} | Stop-Process
}
but I got this error message after executing it:
Invoke-Command : One or more computer names is not valid. If you are trying to
pass a Uri, use the -ConnectionUri parameter or pass Uri objects instead of
strings.
At C:\powerShell\stop-process.ps1:4 char:15
+ Invoke-Command <<<< -ComputerName \\srvwebui3 -ScriptBlock { Get-Process | Where-Object {$_.Path -like "\\gaia\netlims$\Autolims\MainRls\Bin\HttpServer.exe"} | Stop-Process }
+ CategoryInfo : InvalidArgument: (System.String[]:String[]) [Invoke-Command], ArgumentException
+ FullyQualifiedErrorId : PSSessionInvalidComputerName,Microsoft.PowerShell.Commands.InvokeCommandCommand
Here a PowerShell code that worked:
Invoke-Command -ComputerName <computerName> -ScriptBlock {
Get-Process | Where-Object {
$_.Path -like \\bbb\abab$\bs\MainRls\Bin\HttpServer.exe"
} |
Stop-Process -Force
}

Getting a specific service recovery option for a list of servers

Apologies in advance for errors. I'm still learning Powershell.
I'm trying to check a specific service recovery options for a list of servers in AD
$credential = Get-Credential
$servers = Get-ADComputer -Filter * -properties * | ?{$_.OperatingSystem -match "server"} | ft name -hidetableheaders | out-string
$Results = #()
foreach ($Server in $Servers)
{
Invoke-command -cn $server -credential $credential -ScriptBlock {Get-WMIObject win32_service |
Where-Object {$_.description -imatch "nscli" -and $_.startmode -eq "Auto"}; foreach ($service in $services){sc.exe qfailure $service.name}}
}
I'm getting the following error
Invoke-command : One or more computer names are not valid. If you are trying to pass a URI, use the -ConnectionUri parameter, or pass URI objects
instead of strings.
At line:1 char:32
+ foreach ($Server in $Servers) {Invoke-command -cn $server -credential $credentia ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (System.String[]:String[]) [Invoke-Command], ArgumentException
+ FullyQualifiedErrorId : PSSessionInvalidComputerName,Microsoft.PowerShell.Commands.InvokeCommandCommand
If I run the command directly on each server, I don't have any issues.
Invoke-command -cn EXCHANGE -credential $credential -ScriptBlock {$services = Get-WMIObject win32_service | Where-Object {$_.description -imatch "nscli" -and $_.startmode -eq "Auto"}; foreach ($service in $services){sc.exe qfailure $service.name}}
[SC] QueryServiceConfig2 SUCCESS
SERVICE_NAME: NSClientpp
RESET_PERIOD (in seconds) : 0
REBOOT_MESSAGE :
COMMAND_LINE :
FAILURE_ACTIONS : RESTART -- Delay = 120000 milliseconds.
RESTART -- Delay = 120000 milliseconds.
Because I'm using sc.exe, I'm unsure how to output the list into a csv format but at least, I can get some information of which servers the service failure restart aren't set accordingly
Thanks in advance
Cheers
G
Since Invoke-Command doesn't support the -WhatIf switch, your best bet is to echo the server name on console to see the server name that causes failure. In the debugging statement, the server name is enclosed withing single quotes ' for, say, extra whitespace is easier to see. Like so,
foreach ($Server in $Servers)
{
Write-host $("Now processing server '{0}' " -f $Server)
Invoke-command ...
}
You could also try to write the Invoke-Command statements to console and copy-paste those to another a Powershell session to see which, if any, is the failing one.
For what it is worth, you seem to use variables $Server and $server (note the upper/lowercase difference). Though variable names are not case sensitive in Powershell, you might have uninitialized variables caused by simple typos. To guard against such, use Set-StrictMode. It will cause Powershell to complain about uninitialized variables, which commonly are caused by mistyping variable names.
Got it working. Should have responded earlier. Thanks guys.
# Get the credential
$Credential=Get-Credential
# Collect the server list
$Servers = Get-ADComputer -Filter * -Properties operatingsystem | Where operatingsystem -match 'server'
$Results = #()
## Check service status
$Results = foreach ($Server in $Servers)
{Invoke-Command -ComputerName $Server.Name –Ea 0 -Credential $Credential {Get-Service |?{$_.DisplayName –match “nscli”} }}
## Create a csv report
$Results| Sort PSComputerName | select PSComputerName, DisplayName, Name, Status |Export-Csv nsclient_service.csv -NoTypeInformation -UseCulture
# Check the recovery options for NSclient service on each Server
foreach ($Server in $Servers)
{ write-host "Checking " $Server.Name;
Invoke-Command -ComputerName $Server.Name –Ea 0 -Credential $Credential `
{$services = Get-WMIObject win32_service | Where-Object {$_.name -imatch "nscli" -and $_.startmode -eq "Auto"}; `
foreach ($service in $services){sc.exe qfailure $service.name}}
}

Stopping & Restarting Services Remotely Using Set-Service

I've got a list of 10-15 services that I routinely need to restart on 6 servers. I have a script that calls a list of services, then calls a list of the servers, and then stops all the services:
$Services = Get-Content -Path "C:\Powershell\Services.txt"
$Machines = Get-Content -Path "C:\Powershell\Machines.txt"
Get-Service -Name $Services -ComputerName $Machines | Set-Service -Status Stopped
I then have another separate script to start them up again:
$Services = Get-Content -Path "C:\Powershell\Services.txt"
$Machines = Get-Content -Path "C:\Powershell\Machines.txt"
Get-Service -Name $Services -ComputerName $Machines | Set-Service -Status Running
I've checked around and can't seem to find a way of putting this into a single script. As I understand, Set-Service only has the ability to Stop, Start & Pause services, not restart them at the same time.
Any ideas? I might be missing something completely obvious.
To restart services simply use Restart-Service:
$Services = Get-Content -Path "C:\Powershell\Services.txt"
$Machines = Get-Content -Path "C:\Powershell\Machines.txt"
Get-Service -Name $Services -ComputerName $Machines | Restart-Service
Since according to the comments PowerShell v6 has removed support for remote access from the *-Service cmdlets you need to resort to Invoke-Command for remote execution when running v6 or newer, like this:
Invoke-Command -Computer $Machines -ScriptBlock {
Get-Service -Name $using:Services -ErrorAction SilentlyContinue |
Restart-Service
}
or like this:
Invoke-Command -Computer $Machines -ScriptBlock {
Restart-Service $using:Services -ErrorAction SilentlyContinue
}
Another option would be WMI:
$fltr = ($Services | ForEach-Object { 'Name="{0}"' -f $_ }) -join ' or '
Get-WmiObject Win32_Service -Computer $Machines -Filter $fltr | ForEach-Object {
$_.StopService()
$_.StartService()
}
I am with Ansgar, this should work
$Services = Get-Content -Path "C:\Powershell\Services.txt"
$Machines = Get-Content -Path "C:\Powershell\Machines.txt"
foreach ($service in $services){
foreach ($computer in $Machines){
Invoke-Command -ComputerName $computer -ScriptBlock{
Restart-Service -DisplayName $service}
}
}
it is a little messy but should give you a starting point
Sorry I forgot to take time to explain what is going on, so you import each of your txt docs and then it will process for each service and each computer and restart the services.
You can try this single liner command:
Get-Content .\services.txt | %{Get-WmiObject -Class Win32_Service -ComputerName (Get-Content .\computers.txt) -Filter "Name='$_'"} | %{$_.StopService()}; Get-Content .\services.txt | %{Get-WmiObject -Class Win32_Service -ComputerName (Get-Content .\computers.txt) -Filter "Name='$_'"} | %{$_.StartService()}

Powershell - Check on Remote Process, if done continue

As part of a backup operation, I am running the 7zip command to compress a folder into a single .7z file. No problems there as I am using the InVoke-WMIMethod.
Example:
$zip = "cmd /c $irFolder\7za.exe a $somedirectory.7z $somedirectory"
"InVoke-WmiMethod -class Win32_process -name Create -ArgumentList $zip -ComputerName $remotehost"
My problem comes in as my script continues, the 7za.exe process hasn't completed. I am then attempting to copy the item off of the remote system and it is either incomplete or fails.
Can someone point me in the direction to figure out how to identify if the 7za.exe process is still running, wait until it is dead, then proceed with the rest of my script?
I can grasp pulling the process from the remote system via...
get-wmiobject -class Win32_Process -ComputerName $remotehost | Where-Object $_.ProcessName -eq "7za.exe"}
Not sure how to turn that into usable info for my issue.
Answer UPDATE: (thx to nudge by #dugas)
This will do it with some feedback for those that need it...
do {(Write-Host "Waiting..."),(Start-Sleep -Seconds 5)}
until ((Get-WMIobject -Class Win32_process -Filter "Name='7za.exe'" -ComputerName $target | where {$_.Name -eq "7za.exe"}).ProcessID -eq $null)
You can invoke the Wait-Process cmdlet on the remote computer with the Invoke-Command cmdlet. Example:
$process = Invoke-WmiMethod -Class Win32_Process -Name create -ArgumentList notepad -ComputerName RemoteComputer
Invoke-Command -ComputerName RemoteComputer -ScriptBlock { param($processId) Wait-Process -ProcessId $processId } -ArgumentList $process.ProcessId
Since you mentioned using Invoke-Command is not an option, another option is polling.
Example:
$process = Invoke-WmiMethod -Class Win32_Process -Name create -ArgumentList notepad -ComputerName hgodasvccr01
$processId = $process.ProcessId
$runningCheck = { Get-WmiObject -Class Win32_Process -Filter "ProcessId='$processId'" -ComputerName hgodasvccr01 -ErrorAction SilentlyContinue | ? { ($_.ProcessName -eq 'notepad.exe') } }
while ($null -ne (& $runningCheck))
{
Start-Sleep -m 250
}
Write-Host "Process: $processId is not longer running"
You should be able to do it with a do... while loop that just sleeps until the process is finished.
do {
"waiting"
start-sleep 10
} while (gwmi -class win32_process -ComputerName $remotehost | Where ProcessName -eq "7za.exe")

Interesting trouble with windows services and the Stop-Process cmdlet

We have a few home-brewed windows services over here. One of them is problematic, in that it won't always stop when asked. It gets stuck in the 'Stopping' state sometimes.
Using powershell we're retrieving its PID and using the Stop-Process cmdlet to kill the related process, but that's not working either.
Instead we get a message about a service named System.ServiceProcess.ServiceController.Name which obviously isn't our service, but the PID it references is.
Here's what we're doing to get our service to stop. First, we use the Get-Service cmdlet:
$ServiceNamePID = Get-Service -ComputerName $Computer | where { ($_.Status -eq 'StopPending' -or $_.Status -eq 'Stopping') -and $_.Name -eq $ServiceName}
Then, with that ServiceNamePID, we get the PID and use that in the Stop-Process cmdlet
$ServicePID = (get-wmiobject win32_Service -ComputerName $Computer | Where { $_.Name -eq $ServiceNamePID.Name }).ProcessID
Stop-Process $ServicePID -force
That's when the Stop-Process cmdlet squawks about Cannot find a process with the process identifier XYZ, when in fact PID XYZ is the correct Process ID for the service, per the task manager. Has anyone seen a problem like this before?
In order to stop a process on a remote machine, use remoting e.g.
Invoke-Command -cn $compName {param($pid) Stop-Process -Id $pid -force } -Arg $ServicePID
This requires remoting to be enabled on the remote PC and the local account has admin price on the remote PC.
Of course, once you're using remoting you could do the script using remoting e.g.:
Invoke-Command -cn $compName {
$ServiceName = '...'
$ServiceNamePID = Get-Service | Where {($_.Status -eq 'StopPending' -or $_.Status -eq 'Stopping') -and $_.Name -eq $ServiceName}
$ServicePID = (Get-WmiObject Win32_Service | Where {$_.Name -eq $ServiceNamePID.Name}).ProcessID
Stop-Process $ServicePID -Force
}