Home > front end >  Seaching windows environment for a specific value
Seaching windows environment for a specific value

Time:07-29

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.

  • Related