PowerShell: Service enumeration based on part of service name from multiple machines - powershell

I know that I can use PowerShell to check service status on multiple services. For example with something like this:
Get-Service -ComputerName server-a, server-b, server-c -Name MyService |
Select Name, MachineName, Status
Can somebody advice how I can modify this so that:
- Enumerate large number of servers like an array or somehow else so that make it more readable than if I put large number of servers in one line.
- Use a wildcard in service name parameter, e.g. "MYSERVICE*"

You can put your servers in a text file such as SERVERS.TXT :
Server-a
Server-b
Server-c
...
And use :
$servers = get-content SERVERS.TXT
Get-Service -ComputerName $servers -Name MyService | Select Name, MachineName, Status
You can do the same for services.

To answer your second question first, the -Name parameter of the Get-Service cmdlet supports wildcards, so you can simply do this to check several services with similar names:
Get-Service -Computer 'server-a', 'server-b', 'server-c' -Name MyService* |
select Name, MachineName, Status
The -Computer parameter accepts an array of strings, so you can read the server list from a file (containing one hostname per line), as JPBlanc suggested:
$computers = Get-Content 'C:\path\to\serverlist.txt'
Get-Service -Computer $computers -Name MyService* | ...
This is probably the best choice, as it separates data from code.
However, there are situations where it's more practical to keep data and code in the same file (e.g. when you move the script around a lot). In a situation like that you can define an array spanning multiple lines like this:
$computers = 'server-a',
'server-b',
'server-c',
...
Get-Service -Computer $computers -Name MyService* | ...

Related

Piping parameters into cmdlet

This was done for testing and we have the solution but I would like to dig deeper.
I have a file list.txt that contains names of computers:
name
computer1
computer2
computer3
...
when I try
Import-Csv .\list.txt | Select-Object -property #{n="computername";e={$_.name}} | Get-Service
we get an error "Get-Service : Cannot find any service with service name '#{computername=computer1}'." Which I understand as Get-Service trying to map computername=computer1 to the parameter "name" (name="computername=computer1") even though the parameter "computername" is specified.
My solution was to add the "name" parameter and it works as expected
Import-Csv .\list.txt | Select-Object -property #{n="computername";e={$_.name}} | Get-Service -name *
My question is, why? Get-Service should accept pipeline input byPropertyName and it recognizes computername. Why doesn't it bind it unless I specify another parameter? Neither "name", nor "computername" is required. Also
Get-Service
and
Get-Service -computername "computer1"
both work without specifying "name".

Search all servers for service account

There has to be a better way
$server = (Get-ADComputer -Filter * -Properties *).name
foreach ($s in $server)
{
Get-WmiObject Win32_Service -filter 'STARTNAME LIKE "%serviceaccount%"' -computername $s
}
I want to search all servers on the domain for a service account. The above kind of does what I'm looking for but it doesnt return what server the services account was found on. Thanks in advance.
here's what i meant about using Get-Member to find the object properties that would give you the info you want. [grin]
this could be sped up considerably by giving the G-WO call a list of systems. i wasn't ready to code that just now. lazy ... [blush]
what it does ...
sets the account to look for
i only have the LocalSystem and NetworkService accounts listed on my services. [grin]
sets the computer list to search
you will likely use Get-ADComputer. make sure to either use the property name in the loop OR to make your query return only the actual name value.
i only have one system, so my list is 3 different ways to get to the same computer.
loops thru the systems
call G-WO to get the service[s] that use the target account
builds a [PSCustomObect] with the wanted properties
sends that to the $Result collection
shows that on screen
the code ...
$TargetAccount = 'LocalSystem'
$ComputerList = #(
'LocalHost'
'127.0.0.1'
$env:COMPUTERNAME
)
$Result = foreach ($CL_Item in $ComputerList)
{
# i didn't want a gazillion services, so this uses array notation to grab the 1st item
# if you want all the items, remove the trailing "[0]"
$GWMI_Result = #(Get-WmiObject -Class Win32_Service -Filter "STARTNAME LIKE '%$TargetAccount%'" -ComputerName $CL_Item)[0]
[PSCustomObject]#{
ComputerName = $GWMI_Result.SystemName
AccountName = $GWMI_Result.StartName
ServiceName = $GWMI_Result.Name
}
}
$Result
output ...
ComputerName AccountName ServiceName
------------ ----------- -----------
MySysName LocalSystem AMD External Events Utility
MySysName LocalSystem AMD External Events Utility
MySysName LocalSystem AMD External Events Utility

Get Service from remote machines in a domain

Trying to get list of all machines in a Domain with a certain service
tried via all posts in here, helped per one machine, but if i use a text file with multiple machines, it failes
$computers = Get-Content c:\script\computers.txt
$service = "*crystal*"
foreach ($computer in $computers) {
$servicestatus = Get-Service -ComputerName $computer -Name $service
}
$Data = $servicestatus | Select-Object Name,Machinename | Format-Table -AutoSize
Write($Data) | Out-File c:\script\output.txt -Append
Expected list of machines with service in table, instead got error:
This operation might require other privileges
same script, but with a direct machine name, works like a charm.
Any clue what is wrong?
Why not use:
Invoke-Command -ComputerName $computers -ScriptBlock {Get-Service -Name *crystal*}
Eventually you may store the result from invoke into a variable and work with it.
The benefit of using Invoke-Command, insted of foreach is that Invoke works in parallel, while foreach is serial ...
Hope it helps!
Best regards,
Ivan

Get-WMIObject include computer name

I'm trying out a script to go grab installed software on servers remotely. Problem is I want it to output certain attribs including the computer name but I can't seem to figure out how to get the name inserted.
Here is what I have so far...
$servers = Get-QADComputer -SearchRoot "OU=servers,OU=mydomain:-),DC=COM" | Select Name
...which works fine of course. Then...
$servers | % {Get-WMIObject -Class Win32Reg_AddREmovePrograms} | select Displayname,Version,InstallDate,PSComputerName
... which provides the full list of software installed on all servers in that OU but the PSComputerName becomes MY COMPUTER (the computer I run the query from - not the computername of the system being queried). The goal is to have the servername the software is installed on on each line item of software. I've asked professor Google and don't seem to see anything helpful (or anything that I understand anyway).
Hope this makes sense. semi-amateur PS script writer so hopefully this is easy for you guys. Thanks in advance for your help
Your command:
Get-WMIObject -Class Win32Reg_AddREmovePrograms
Does not specify computer to query, so it just query computer command being executed on. Thus PSComputerName display MY COMPUTER, as MY COMPUTER is computer being queried. You have to specify -ComputerName parameter to Get-WMIObject cmdlet to query specific computer. And -ComputerName parameter accept array of computer names, so you can put array of computer names to it instead of using ForEach-Object cmdlet and query one computer at time.
Since the object returned from the WMI call doesn't contain the computer you made the request on, you need to include it yourself from include your ForEach-Object (%) block. You could use Add-Member to add it yourself, then do your Select-Object outside like you're doing now:
$servers | % {
Get-WMIObject -Class Win32Reg_AddREmovePrograms -ComputerName $_ |
Add-Member -MemberType NoteProperty -Name ComputerName -Value $_ -PassThru
} | select Displayname,Version,InstallDate,ComputerName
Another way is to move the Select-Object to inside the block and do it within there, by creating a new property on the fly with a hashtable:
$servers | % {
Get-WMIObject -Class Win32Reg_AddREmovePrograms -computername $_ |
Select-Object Displayname,Version,InstallDate,#{Name='ComputerName';Expression={$_}}
}

How to check if a particular service is running in a remote computer using PowerShell

I have 3 servers, running 3 services:
SERVER-A running serv1.exe service
SERVER-B running serv2.exe service
SERVER-C running serv3.exe service
Using PowerShell how can I query each service to check if they are running and output the information to a text file?
If they all have the same name or display name you can do it in one command. If not you need to run 3 commands.
If all have the same name or display name:
Get-Service -ComputerName server-a, server-b, server-c -Name MyService |
Select Name, MachineName, Status
If they have different names or display names:
I would do this --
#{
'server-a' = 'service-a'
'server-b' = 'service-b'
'server-c' = 'service-c'
}.GetEnumerator() | ForEach-Object {
Get-Service -ComputerName $_.Name -Name $_.Value
} | Select Name, MachineName, Status
To output to a text file use ... | Set-Content ~\Documents\Service_Status.txt where ... is one of the above.
Note - your account will need to have privileges to query the remote machines.
There are several ways to achieve this. I am using a hash of the values since you mentioned that the server to service mapping is always one to one.
$svrHash = #{"SERVER-01"="winmgmt";"SERVER-02"="Wecsvc"}
$svrHash.Keys
| ForEach-Object {Get-Process -ComputerName $_ -Name $svrHash[$_] -Ea SilentlyContinue}
| Select ProcessName
| Out-File C:\Scripts\test.txt
You need to use the service name and not the .exe name.