To complement Santiago Squarzon's helpful answer with an optimization:
# Prompt until a valid service status identifier is entered.
do {
try {
[System.ServiceProcess.ServiceControllerStatus] $sStatus =
Read-Host "Please specify the desired service status (e.g., Running or Stopped)"
break # A valid value was entered, exit the loop
} catch { }
Write-Warning "Unknown status; please specify one of: $([Enum]::GetNames([System.ServiceProcess.ServiceControllerStatus]))"
} while ($true)
# Now output the names of all services that are in the specified state, if any:
(Get-Service | Where-Object Status -eq $sStatus).Name
Casting the user input (which is always a string) to type [System.ServiceProcess.ServiceControllerStatus]
(the type of the .Status
property of the objects returned by Get-Service
) is used to ensure that a valid service-status identifier was entered.
As for what you tried:
Leaving the inefficiency of calling Get-Service
twice aside, your primary problem was the use of the .Contains()
.NET array method (implemented via the IList
interface):
.Contains()
performs no on-demand type conversions, so looking for a string ($sstatuss
) in your array of [System.ServiceProcess.ServiceControllerStatus]
values ($statusbank
) never succeeds.
By contrast, PowerShell's -contains
operator does perform on-demand type conversions (as PowerShell generally does) and is notably also case-insensitive (as PowerShell generally is). The same applies to functionally equivalent, but operands-reversed -in
operator.
To illustrate the difference:
# Sample array with [System.ServiceProcess.ServiceControllerStatus] elements.
$array = [System.ServiceProcess.ServiceControllerStatus]::Running,
[System.ServiceProcess.ServiceControllerStatus]::Stopped
# WRONG.
$array.Contains('running') # !! always $false with a [string] as input
# OK.
$array -contains 'running' # -> $true - on-demand type conversion
# from string to [System.ServiceProcess.ServiceControllerStatus]
In a nutshell: -contains
is in effect using the -eq
operator against each element behind the scenes, so the latter's automatic type conversions and case-insensitivity apply. See the bottom section of this answer for more information about -contains
and -in
.
Pitfall: Due to having the same name, there's potential for confusion with the .Contains()
string method, which functions differently, however: it performs literal substring matching, and there is no direct operator equivalent in PowerShell for that - see this answer.
Also:
Format-*
cmdlets output objects whose sole purpose is to provide formatting instructions to PowerShell's output-formatting system - see this answer. In short: only ever use Format-*
cmdlets to format data for display, never for subsequent programmatic processing.
Write-Host
is typically the wrong tool to use, unless the intent is to write to the display only, bypassing the success output stream and with it the ability to send output to other commands, capture it in a variable, or redirect it to a file. To output a value, use it by itself; e.g., $value
instead of Write-Host $value
(or use Write-Output $value
, though that is rarely needed); see this answer