I want to search the windows environment variables for a specific string
Get-ChildItem -Path Env: | TEE-OBJECT -variable newvar1 | grep windir $newvar1
It works for first time
STDIN
windir C:\WINDOWS
and then fails the subsequent times
grep: Could not open 'System.Collections.DictionaryEntry'
How do i remove old variables from the dictionary (if that is the problem)?
CodePudding user response:
You an try :
Get-ChildItem -Path Env: | Where-object {$_.value -like 'C:\Users*'}
Get-ChildItem
returns a list of objects with properties Name
and value
. Then Where-object, allow you to filter on these properties, $_
representthe object, you can choose the operator (in this case -like
) in the list of Powershell operators).
CodePudding user response:
Part 1 - Root Cause
Your core problem is grep windir $newvar1
- the command line parameters for grep
are (from https://man7.org/linux/man-pages/man1/grep.1.html):
SYNOPSIS
grep [OPTION...] PATTERNS [FILE...]
DESCRIPTION
grep searches for PATTERNS in each FILE.
You're asking grep to search in a file ($newvar1
), not the input stream. Each entry in $newvar1
, gets serialised as the literal string System.Collections.DictionaryEntry
so grep is basically looking for a file called System.Collections.DictionaryEntry
, which doesn't exist.
Part 2 - Solution
The best bet is to go full idiomatic PowerShell and use @JPBlanc's answer, but if you're really wedded to grep just remove the trailing $newvar
to use the input stream (stdin) instead of a file for input:
Get-ChildItem -Path Env: `
| TEE-OBJECT -variable newvar1 `
| grep windir
or, if you don't actually need the values stored in $newvar1
for downstream processing, just simply:
Get-ChildItem -Path Env: `
| grep windir
Part 3 - Why no error the first time?
Your original command works the first time because $newvar1
isn't defined yet, so it's equivalent to:
Get-ChildItem -Path Env: `
| TEE-OBJECT -variable newvar1 `
| grep windir $null
... so grep is defaulting to searching the input stream (stdin) rather than a file.
You can confirm this if you enable strict mode - you'll get this error from PowerShell instead:
Set-StrictMode -Version "Latest";
Get-ChildItem -Path Env: `
| TEE-OBJECT -variable newvar1 `
| grep term $newvar1
# InvalidOperation:
# Line |
# 3 | | grep term $newvar1
# | ~~~~~~~~
# | The variable '$newvar1' cannot be retrieved because it has not been set.
The second time you run the commnad, $newvar1
is already initialised with the results from the first time, so it's equivalent to:
Get-ChildItem -Path Env: `
| TEE-OBJECT -variable newvar1 `
| grep windir "System.Collections.DictionaryEntry"
which, as we've seen, tells grep to look for a file called System.Collections.DictionaryEntry
, and results in an error.
Part 4 - More details
Note that $newvar1
isn't defined in the first call to grep because Tee-Object
only creates the variable in its End block once it's processed all of its pipeline input (see the source code for Tee-Object.cs on GitHub), which doesn't happen until the entire pipeline has been processed, including the downstream calls to grep.
Not that it's very useful, but you can force the first command to fail by doing this:
(Get-ChildItem -Path Env: | TEE-OBJECT -variable newvar1) `
| grep term $newvar1
# /usr/bin/grep: System.Collections.DictionaryEntry: No such file or directory
Wrapping the first two expressions in a Grouping Operator forces the pipeline inside to be fully evaluated first, which means Tee-Object
's End block creates the $newvar1
variable before grep is invoked, and we get the file-searching behaviour instead of the input stream behaviour.