1

Hi guys its maybe a easy question for you but im newbie from powershell so can you pls help me?

In school I got an assignment where I needed to make a menu, a script that could search from service to status, and a script that could search from status to service, and it looks like this:

    elseif ($menu -eq "2") {
    $statusbank = (Get-Service).Status
    $sstatuss = Read-Host "Bitte geben Sie ein Status ein z.B Running/Stopped"

if ($statusbank.Contains([string]$sstatuss)) {
        $Information = (Get-Service | Where-Object {$_status -eq $sstatuss}).Name | format-list -property Name
        Write-Host  $Information
    }
}

i really dont understand where my problem is. It dosn't work: It doesn't do anything and then just ends the script If i debug, i only see it will skip this, even they are a lot of true value in $statusbank :

if ($statusbank.Contains([string]$sstatuss)) {

2 Answers2

1

Try using this instead:

elseif ($menu -eq "2")
{
    $statusbank = Get-Service
    $sstatuss = Read-Host "Bitte geben Sie ein Status ein z.B Running/Stopped"

    if($sstatuss -match '^(Running|Stopped)$' -and $sstatuss -in $statusbank.Status)
    {
        $statusbank | Where-Object Status -EQ $sstatuss |
        Format-Table -Property Name,Status
    }
}
Santiago Squarzon
  • 41,465
  • 5
  • 14
  • 37
  • 1
    @kaiwenShao yup, no problem :) `.Contains(...)` wouldn't work on the Service's Status array that's why I used `-in` instead. If this answer was helpful to you please consider [accepting it](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work/5235#5235). – Santiago Squarzon Jul 15 '21 at 14:22
1

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

mklement0
  • 382,024
  • 64
  • 607
  • 775