TNPMCHammer
TNPMCHammer

Reputation: 3

How to use Where-Object with StartsWith to filter Powershell command outputs

I have a powershell script written by somebody else that makes use of uses the output of a command to filter and extract the results. I think I understand what it is attempting to do but not why I am getting an error.

pertinent part of Script is

$dockerInfo = (docker info)
$dockerOsMode = ($dockerInfo | Where-Object { $_.StartsWith('OSType: ') }).SubString(8)

I however get the error message

Checking Docker Service Settings...
You cannot call a method on a null-valued expression.
At C:\Users\MichaelC\Documents\DockerCleanup.ps1:29 char:1
+ $dockerOsMode = ($dockerInfo | Where-Object { $_.StartsWith('OSType:  ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : InvokeMethodOnNull

My understanding of the error message is that the $dockerInfo variable is null but it isnt. If I run the variable directly I can see its output.

PS C:\Users\MichaelC> $dockerinfo
Client:
 Version:    24.0.4
 Context:    default
 Debug Mode: false

Server:
 Containers: 2
  Running: 0
  Paused: 0
  Stopped: 2
 Images: 47
 Server Version: 24.0.4
 Storage Driver: windowsfilter
  Windows:
 Logging Driver: json-file
 Plugins:
  Volume: local
  Network: ics internal l2bridge l2tunnel nat null overlay private transparent
  Log: awslogs etwlogs fluentd gcplogs gelf json-file local logentries splunk syslog
 Swarm: inactive
 Default Isolation: process
 Kernel Version: 10.0 17763 (17763.1.amd64fre.rs5_release.180914-1434)
 Operating System: Microsoft Windows Server Version 1809 (OS Build 17763.5329)
 OSType: windows
 Architecture: x86_64
 CPUs: 6
 Total Memory: 31.98GiB
 Name: MCNAV
 ID: 5dbd48b8-ca1b-44bf-9495-5a504c435305
 Docker Root Dir: D:\docker
 Debug Mode: false
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false
 Product License: Community Engine

Is there some other global setting that I need to have turned on to be able to use the filter command on the Command output

Upvotes: 0

Views: 1103

Answers (3)

mclayton
mclayton

Reputation: 10085

The exception is being thrown because

($dockerInfo | Where-Object { $_.StartsWith('OSType: ') })

returns $null - i.e. doesn't return any matches (for reasons mentioned by commenters re the leading space in the text), meaning your Substring is equivalent to:

$null.SubString(8)

And that's what's giving the exception.

There's some options given by commenters and other answers, but here's a quick and dirty one - trim the lines before you compare them:

$dockerOsMode = ($dockerInfo.Trim() | Where-Object { $_.StartsWith('OSType: ') }).Substring(8)
#                           ^^^^^^^

$dockerOsMode
# Windows

This uses Member Access Enumeration to build a new array of text lines that contain the results of invoking Trim() on each line of text the $dockerInfo variable, and then passes the trimmed values into Where-Object.

Upvotes: 0

js2010
js2010

Reputation: 27566

I would do something like this, splitting on whitespace and taking the 2nd element. Note that startswith() is case sensitive, like most of those string methods.

(-split (' OSType: windows' | select-string ostype:))[1]

windows

Upvotes: 0

lit
lit

Reputation: 16266

If $dockerInfo is null, this will still produce $dockerOsMode as null.

$dockerOsMode = $dockerInfo | ForEach-Object {
    if ($_ -match '^\s*OSType:\s*(.*)') { $Matches[1] }
}

Upvotes: 0

Related Questions