PowerShell check for service existance on remote machine - reliably? - powershell

I'm currently trying to check a bunch of remote machines for the existence of certain services. Currently that process is pretty slow (as in > 1 hour for a few hundred machines) which isn't much of a problem but also unreliable (which is a problem).
Some of those machines might be blocking access, turned off or might in some other way limit access to query for the services.
The current approach is to check with Get-Service and as it has proven to be unreliable to also check with Get-WmiObject as well as Get-CimInstance.
The problem is that they don't support timeouts so if a server is just unresponsive it will take quite a bit of time to get a response and because all three options might work or not depending on the machine there really isn't an option to only run one. As one of them might succeed where the others failed I need to check the results of all three calls.
Would anyone have an idea on how to do a sort of preflight check to figure out which command might work or if there is a different approach to checking for the existence of a service that might be more reliable?
The current approach looks akin to this (simplified):
$error.Clear()
$serviceExists = $false
$server = "localhost"
$serviceQuery = Get-Service -ErrorAction SilentlyContinue -Name WinRM -ComputerName $server
$wmiQuery = Get-WmiObject -ErrorAction SilentlyContinue -Class Win32_Service -Filter "Name = 'WinRM'" -ComputerName $server
$cimQuery = Get-CimInstance -ErrorAction SilentlyContinue -ClassName Win32_Service -Filter "Name = 'WinRM'" -ComputerName $server
if ($error.Count -ge 1) {
Write-Output "An error occurred while check for the service existence on $server"
}
if (
($serviceQuery | Where Name -eq 'WinRM') -ne $null -or
($wmiQuery | Where Name -eq 'WinRM') -ne $null -or
($cimQuery | Where Name -eq 'WinRM') -ne $null
) {
$serviceExists = $true
}
As far as I can tell it might be that Get-Service internally uses (the same approach as) Get-WmiObject and Get-CimInstance but I wasn't able to find documentation on that. The machine currently use PowerShell 5.x, PowerShell remoteing might or might not be configured on the servers that are being queried for the service existence.
Edit: Get-Service is unreliable because it might not indicate that there was an issue and just return $null without indicating that there actually was a problem. Also while it might fail one of the other options might still work.

Related

How do i get power shell to show a few services from my servers and not them all

this is my code i want it to show a few services from my servers but it keeps showing all of them. i tried using -Name but power shell 7 keeps saying that doesn't exist please help
$offlineServices = (Invoke-Command -ComputerName $server.Name {Get-service [string]$server.Value | `
Where-Object{$_.status -eq 'Stopped'}} ).Name
Get-Service can be used directly against remote servers, like this:
Get-Service -Name $server.Value -ComputerName $server.Name |
Where-Object Status -eq 'Stopped'
If you want to stick with your original remoting technique, you need to use the using modifier:
$offlineServices = (Invoke-Command -ComputerName $server.Name -Script {Get-service $using:server.Value |
Where-Object Status -eq 'Stopped'}).Name
NOTE: you should also remove the backtick before Where-Object as it isn't needed and might cause you issue later when modifying/debugging the code.

Powershell to query specific Service in enterprise?

Good day good people.
Would someone please help me out I am trying to PS our enterprise servers to find all assets with a particular service on it and having no luck.
I tried
$servicename = "SERVICE_NAME"
$list = get-content "c:\security\comp_list.txt"
foreach ($server in $list) {
if (Get-Service $servicename -computername $server -ErrorAction 'SilentlyContinue'){
Write-Host "$servicename exists on $server
}
Any suggestions would be greatly appreciated. I'm still fairly new to PS.
My accepted answer to why Get-Service -ComputerName fails can be found in the link below and the resolution to the issue.
Powershell Results to Slack via Webhook question - Remote Server results
Summary
Differences between Windows PowerShell 5.1 and PowerShell 7.x
Please Note In Windows 7.2 the Get-Service command made use of DCOM and such functionality like '-ComputerName' is removed.
https://learn.microsoft.com/en-us/powershell/scripting/whats-new/differences-from-windows-powershell?view=powershell-7#remove--computername-from--service-cmdlets-5090
$server = $env:Computername
Invoke-Command -Computername $server -Scriptblock {Get-Service | where status -eq 'started;}
Get-Service cmdlet
The cmdlet gets the members, the properties and methods, of objects
get-service | get-member | sort Name
Names of services that start / contain 'App'
$Results = Get-Service -Name App | Select Name

PowerShell script to detect Active instances of BizTalk send port

I have a PowerShell script to detect active instances of send port running in BizTalk. I am struggling with syntax to query the MSBTS_ServiceInstance to find the active instances of this send port.
Can anyone help me as to how to subsitute the name of the send port in the where clause or the filter clause please ?
[ARRAY]$active = get-wmiobject MSBTS_ServiceInstance -namespace 'root\MicrosoftBizTalkServer' -filter '(ServiceStatus = 2) and how to search by name' -ErrorAction SilentlyContinue
Write-Host "Active Instances:" $active.Count
This should do the trick
[ARRAY]$active = get-wmiobject MSBTS_ServiceInstance -namespace 'root\MicrosoftBizTalkServer' -filter {ServiceStatus = 2 and ServiceName = "port name"} -ErrorAction SilentlyContinue
Please see Class definition and PowerShell syntax
However I personaly prefer using Microsoft.BizTalk.Operations.dll with PowerShell to perform this kind of queries.

How to find the version of Trend from the Registry of a specific PC?

I was wondering if there is a way to find a registry value of a specific computer. The only way I could find is entering a pssession and then exiting.
$Computer = Read-Host "Enter the PC Name: "
$connection=test-connection -ComputerName $Computer -Quiet
if($connection -eq $True) {
Enter-PSSession $Computer
$TrendServer= Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\TrendMicro\PC-cillinNTCorp \CurrentVersion | Select Server
write-output $TrendServer
if($TrendServer -ne $null){
Exit-PSSession
}
} else{Write-Output "Computer is not available. Please check Lan Sweeper "}
If it is installed using Windows Installer, you can use WMI, though this class is known to be quite slow:
Get-CimInstance -Query "SELECT * FROM Win32_Product WHERE Name = 'TrendMicro'" `
-ComputerName $computer
Change the name from 'TrendMicro' to whatever it actually is (I don't have it installed to check), and for older versions of PowerShell, use Get-WmiObject instead of Get-CimInstance.
Get more information here: Working with Software Installations

test-connection that supports wildcard? workaround?

trying to see if anyone has a known workaround for using the test-connection cmdlet in powershell to ping wildcard entries in DNS.
I'm trying to clean out our DNS db and exported a list from our BIND server and am in the process of just pinging through the 600+ machines to see if anything responds. I made my own simple script but have also found one that works slightly better on this forum. The script works but the cmdlet help files state that the -computername parameter does not support wildcards and sure enough, when i run the script all CNAME records are reporting down/false when they actually should be responding. The code I'm using is below and is kind of messy but I just needed something quick and it works, but I've included it below for reference:
Get-Content -path C:\Work\testy.txt | ForEach-Object { Test-Connection -ComputerName $_ -Count 1 -AsJob } | Get-Job | Receive-Job -Wait | Select-Object #{Name='ComputerName';Expression={$_.Address}},#{Name='Reachable';Expression={if ($_.StatusCode -eq 0) { $true } else { $false }}} |out-file -FilePath c:\work\TEST.txt
As pointed out by briantist, any non-existing record name will do. You could generate a GUID to substitute the * in your record name:
"subdomain.domain.tld","*.domain.tld" |ForEach-Object {
Test-Connection -ComputerName $($_ -replace '\*',"$([guid]::NewGuid())")
}
Your expression for whether it's "Reachable" or not can be simplified as well:
#{Name='Reachable'; Expression={[bool]($_.StatusCode -eq 0)}}