Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PowerShell, pipeline compatible Select-String function

This is more about my weak understanding of pipelines and functions than anything, so would appreciate help. As an example:

Get-Service | Select-String win   # fails
Get-Service | Out-String -Stream | Select-String win   # works

I've seen explanations on why the Out-String -Stream is required, but it frustrates me a bit, so I want a function oss that does the Out-String -Stream part. My idea is like this:

function oss { Out-String -Stream }
Get-Service | oss | Select-String win

But this fails. Can someone tell me how to make this work, i.e. make the oss function pipeline compatible?

And from that, how do we then do the following (obviously this doesn't work, but I'm really curious how this would be achieved)?

function slx { Out-String -Stream | Select-String <and allow all of the same switches as Select-String> }
Get-Service | slx win

So that, effectively, slx is a variant of Select-String that always does the Out-String -Stream part as well?

like image 256
YorSubs Avatar asked Nov 01 '20 09:11

YorSubs


People also ask

How do I select a part of a string in PowerShell?

To find a string inside of a string with PowerShell, you can use the Substring() method. This method is found on every string object in PowerShell. The first argument to pass to the Substring() method is the position of the leftmost character. In this case, the leftmost character is T .

How do I search for a string in PowerShell?

You can use it like Grep in UNIX and Findstr in Windows with Select-String in PowerShell. Select-String is based on lines of text. By default, Select-String finds the first match in each line and, for each match, it displays the file name, line number, and all text in the line containing the match.

Is Select-string case sensitive?

Select-String uses the Pattern parameter to specify HELLO. The CaseSensitive parameter specifies that the case must match only the upper-case pattern. SimpleMatch is an optional parameter and specifies that the string in the pattern isn't interpreted as a regular expression.

What does $_ mean in PowerShell?

The “$_” is said to be the pipeline variable in PowerShell. The “$_” variable is an alias to PowerShell's automatic variable named “$PSItem“. It has multiple use cases such as filtering an item or referring to any specific object.

How do I search for a string in a PowerShell pipeline?

The Pattern parameter uses the string About_ as the search criteria. To run the function, type Search-Help. The function's Select-String command displays the output in the PowerShell console. This example searches for a string in a Windows event log. The variable $_ represents the current object in the pipeline.

Can Windows PowerShell accept pipelined input?

Summary: Microsoft MVP, Adam Bertram, talks about accepting pipelined input into Windows PowerShell advanced functions. Microsoft Scripting Guy, Ed Wilson, is here. Today Microsoft MVP, Adam Bertram, returns to talk about accepting pipeline input into advanced Windows PowerShell functions. Note This is the second post in a series.

What is a PowerShell pipeline?

The pipeline is what makes PowerShell so unique. The thought of a pipeline is not new. We've been able to pipe strings from the output of one command to the input of another command for a long time. However, it wasn't until PowerShell came along that we had a language that allowed us to pipe objects from one command to another.

What is steppable pipeline in PowerShell v2?

In some cases, calling it isn’t quite enough and PowerShell V2 delivered the steppable pipeline which can take a PowerShell command (or set of commands piped together) and allow us to run its begin block , process block, and end block, under the control of a function. So a Proxy function looks like this :


Video Answer


2 Answers

I appreciate that you want to learn, so I will not just give you a working solution, but also explain a few things.

It seems like your you have a basic understanding of how functions and the pipeline work. If you want to learn more about it have a look at about_Pipelines and about_Functions (and related help topics), or let me know what in particular you want to know in the comments.

One thing you need to understand though if you are new to Powershell, is that it it's object-based, not text-based. It's objects that are passed through the pipeline, and you should work with them as such, and not convert them to text (unless for file output).

The documentation about Select-String states specifically, that it is meant for finding text in strings and files. But this is not what you are trying to do here. As I said, work with objects, not text. So omit the Out-String. The proper command to filter objects in a pipeline is Where-Object or one of its aliases where or ?.

Example:

Get-Service | where { $_.DisplayName -like *win* }
# in newer Powershell versions, this shorter syntax is also possible:
Get-Service | where DisplayName -like *win*

But as you specifically asked about making a function "pipeline aware", this can be done in several ways. But your problem is not only getting input from the pipeline, but also they way you pass it to Out-String, because the output will change if you pass only one item at a time.

Basically you have to pass the input all at once. So, the simplest way to achieve this in your case is using the $Input automatic variable:

 function oss { $Input | Out-String -Stream }

If you need to process one pipeline item at a time, there are more ways to get pipeline input. For example an advanced function:

function example { 
    process {
        $_ # current item
    }
}

You can also use the parameter attribute to bind the pipeline input to a function parameter:

function example {
    param(
        [Parameter(ValueFromPipeline = $true)]
        $InputObject
    )
    process {
        $InputObject # current item
    }
}

The last way I can think of is using a filter, which is a special kind of function which is specifically designed to perform an operation on each pipeline element:

filter example {
    $_ # current item
}

To learn more about it I recommend a google search which will quickly provide you with useful articles such as Build a PowerShell function for the pipeline or Incorporating Pipelined Input into PowerShell Functions.

If you truly want to build a method that is basically a wrapper for another cmdlet like Out-String or Select-String with all the same switches, you should have a look at proxy functions. But I think this would be overkill for what you're trying to do:

function oss {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline = $true)]
        [psobject]$InputObject
    )
    begin
    {
        try {
            $outBuffer = $null
            if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
            {
                $PSBoundParameters['OutBuffer'] = 1
            }
            # set -Stream switch always
            $PSBoundParameters["Stream"] = $true
            $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Utility\Out-String', [System.Management.Automation.CommandTypes]::Cmdlet)
            $scriptCmd = {& $wrappedCmd @PSBoundParameters }
            $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
            $steppablePipeline.Begin($PSCmdlet)
        } catch {
            throw
        }
    }
    process
    {
        try {
            $steppablePipeline.Process($_)
        } catch {
            throw
        }
    }
    end
    {
        try {
            $steppablePipeline.End()
        } catch {
            throw
        }
    }
}
like image 171
marsze Avatar answered Oct 10 '22 05:10

marsze


Note: This answer complements marsze's helpful answer.


Windows PowerShell v5.1 and PowerShell [Core] v6+ have an oss function built in, which effectively provides the functionality of Out-String -Stream via a proxy function, as shown in @marsze's answer.

  • As an aside: the code that is auto-generated when you scaffold a proxy function has minor flaws as of PowerShell 7.1; in short: the OutBuffer-related code only applies to server-side proxy functions that need to guard against DoS (denial-of-service) attacks, and the throw statements should be $PSCmdlet.ThrowTerminatingError($_) instead - see GitHub issue #10863.

While this helper function is useful, it shouldn't be required in the first place, because Select-String should implicitly operate on formatted output to begin with:

  • That is, for input that isn't already a string (text), Select-String should search the same richly formatted text representation that you see in the console (terminal).

    • Note: As pointed out in marsze's answer, in programmatic use, for robustness, you should take advantage of PowerShell's object-oriented nature and query properties instead, with Where-Object.
      However, for quick-and-dirty interactive use it can be very convenient to search through the for-display representations.
  • GitHub suggestion #10726 proposes just that, though there seem to be backward-compatibility concerns, even though I think there shouldn't be.


You can adapt the proxy-function approach from marsze's answers to properly implement the slx function you envision, as advanced function Select-StringFormatted, aliased to scs (see rationale below; of course, you can also define slx).

Note:

  • The bulk of the code is the auto-generated declaration of the same parameters that Select-String supports; the actual proxying (wrapping) code via Out-String -Stream is minimal.

  • Alias scs is what Select-String's built-in alias sls should have been, given that the official alias prefix for approved verb Select is sc, not ls; in PowerShell [Core] v6+ you an easily verify that with Get-Verb Select. Since the implicit Out-String -Stream behavior should be Select-String's default behavior anyway, I think it makes sense to pick this alias; if/when Select-String gets fixed, you can redefine scs to point to Select-String.

  • All parameters supported as of v7.0 are declared; if you try to use ones only introduced in 7.0 in earlier versions, namely -Culture, -Raw, and -NoEmphasis, they are ignored and a warning is emitted.

  • Example command (compare to the output from Get-Process | sls service):

    PS> Get-Process | scs service  # scs == Select-StringFormatted
    
        395      16     3728      14656              5664   0 SecurityHealthService                                                                                
        360      11     3864       7696               632   0 services                                                                                             
        173      12     3324       8628              2388   0 VGAuthService                                                                                        
    

Note: The function below is also available as an MIT-licensed Gist, and only the latter will be maintained going forward. Assuming you have looked at the linked code to ensure that it is safe (which I can personally assure you of, but you should always check), you can install it as follows:

irm https://gist.github.com/mklement0/46fea9e6e5ef1a3ceaf681c976cb68e3/raw/Select-StringFormatted.ps1 | iex
Set-Alias scs Select-StringFormatted

function Select-StringFormatted {
  <#
    .SYNOPSIS
    Select-String wrapper command that for non-string input searches the
    *formatted* object representations rather than the often useless
    .ToString() representations.

    All Select-String parameters are supported. See the latter's help for more.

    .EXAMPLE
    Get-Process | Select-StringFormatted pwsh

    Output lines that contain "pwsh" in Get-Process' formatted output.

    .LINK
    Select-String

    #>
  [CmdletBinding(DefaultParameterSetName = 'File', HelpUri = 'https://go.microsoft.com/fwlink/?LinkID=2097119')]
  param(
    [ValidateSet('Ordinal', 'Invariant', 'Current', '', 'af', 'af-NA', 'af-ZA', 'agq', 'agq-CM', 'ak', 'ak-GH', 'am', 'am-ET', 'ar', 'ar-001', 'ar-AE', 'ar-BH', 'ar-DJ', 'ar-DZ', 'ar-EG', 'ar-EH', 'ar-ER', 'ar-IL', 'ar-IQ', 'ar-JO', 'ar-KM', 'ar-KW', 'ar-LB', 'ar-LY', 'ar-MA', 'ar-MR', 'ar-OM', 'ar-PS', 'ar-QA', 'ar-SA', 'ar-SD', 'ar-SO', 'ar-SS', 'ar-SY', 'ar-TD', 'ar-TN', 'ar-YE', 'arn', 'arn-CL', 'as', 'as-IN', 'asa', 'asa-TZ', 'ast', 'ast-ES', 'az', 'az-Cyrl', 'az-Cyrl-AZ', 'az-Latn', 'az-Latn-AZ', 'ba', 'ba-RU', 'bas', 'bas-CM', 'be', 'be-BY', 'bem', 'bem-ZM', 'bez', 'bez-TZ', 'bg', 'bg-BG', 'bm', 'bm-ML', 'bn', 'bn-BD', 'bn-IN', 'bo', 'bo-CN', 'bo-IN', 'br', 'br-FR', 'brx', 'brx-IN', 'bs', 'bs-Cyrl', 'bs-Cyrl-BA', 'bs-Latn', 'bs-Latn-BA', 'byn', 'byn-ER', 'ca', 'ca-AD', 'ca-ES', 'ca-FR', 'ca-IT', 'ccp', 'ccp-BD', 'ccp-IN', 'ce', 'ce-RU', 'ceb', 'ceb-PH', 'cgg', 'cgg-UG', 'chr', 'chr-US', 'ckb', 'ckb-IQ', 'ckb-IR', 'co', 'co-FR', 'cs', 'cs-CZ', 'cv', 'cv-RU', 'cy', 'cy-GB', 'da', 'da-DK', 'da-GL', 'dav', 'dav-KE', 'de', 'de-AT', 'de-BE', 'de-CH', 'de-DE', 'de-IT', 'de-LI', 'de-LU', 'dje', 'dje-NE', 'dsb', 'dsb-DE', 'dua', 'dua-CM', 'dv', 'dv-MV', 'dyo', 'dyo-SN', 'dz', 'dz-BT', 'ebu', 'ebu-KE', 'ee', 'ee-GH', 'ee-TG', 'el', 'el-CY', 'el-GR', 'en', 'en-001', 'en-150', 'en-AD', 'en-AE', 'en-AG', 'en-AI', 'en-AL', 'en-AR', 'en-AS', 'en-AT', 'en-AU', 'en-BA', 'en-BB', 'en-BD', 'en-BE', 'en-BG', 'en-BI', 'en-BM', 'en-BR', 'en-BS', 'en-BW', 'en-BZ', 'en-CA', 'en-CC', 'en-CH', 'en-CK', 'en-CL', 'en-CM', 'en-CN', 'en-CO', 'en-CX', 'en-CY', 'en-CZ', 'en-DE', 'en-DG', 'en-DK', 'en-DM', 'en-EE', 'en-ER', 'en-ES', 'en-FI', 'en-FJ', 'en-FK', 'en-FM', 'en-FR', 'en-GB', 'en-GD', 'en-GG', 'en-GH', 'en-GI', 'en-GM', 'en-GR', 'en-GU', 'en-GY', 'en-HK', 'en-HR', 'en-HU', 'en-ID', 'en-IE', 'en-IL', 'en-IM', 'en-IN', 'en-IO', 'en-IS', 'en-IT', 'en-JE', 'en-JM', 'en-JP', 'en-KE', 'en-KI', 'en-KN', 'en-KR', 'en-KY', 'en-LC', 'en-LR', 'en-LS', 'en-LT', 'en-LU', 'en-LV', 'en-ME', 'en-MG', 'en-MH', 'en-MM', 'en-MO', 'en-MP', 'en-MS', 'en-MT', 'en-MU', 'en-MV', 'en-MW', 'en-MX', 'en-MY', 'en-NA', 'en-NF', 'en-NG', 'en-NL', 'en-NO', 'en-NR', 'en-NU', 'en-NZ', 'en-PG', 'en-PH', 'en-PK', 'en-PL', 'en-PN', 'en-PR', 'en-PT', 'en-PW', 'en-RO', 'en-RS', 'en-RU', 'en-RW', 'en-SA', 'en-SB', 'en-SC', 'en-SD', 'en-SE', 'en-SG', 'en-SH', 'en-SI', 'en-SK', 'en-SL', 'en-SS', 'en-SX', 'en-SZ', 'en-TC', 'en-TH', 'en-TK', 'en-TO', 'en-TR', 'en-TT', 'en-TV', 'en-TW', 'en-TZ', 'en-UA', 'en-UG', 'en-UM', 'en-US', 'en-US-POSIX', 'en-VC', 'en-VG', 'en-VI', 'en-VU', 'en-WS', 'en-ZA', 'en-ZM', 'en-ZW', 'eo', 'eo-001', 'es', 'es-419', 'es-AG', 'es-AI', 'es-AR', 'es-AW', 'es-BB', 'es-BL', 'es-BM', 'es-BO', 'es-BQ', 'es-BR', 'es-BS', 'es-BZ', 'es-CA', 'es-CL', 'es-CO', 'es-CR', 'es-CU', 'es-CW', 'es-DM', 'es-DO', 'es-EA', 'es-EC', 'es-ES', 'es-FK', 'es-GD', 'es-GF', 'es-GL', 'es-GP', 'es-GQ', 'es-GT', 'es-GY', 'es-HN', 'es-HT', 'es-IC', 'es-KN', 'es-KY', 'es-LC', 'es-MF', 'es-MQ', 'es-MS', 'es-MX', 'es-NI', 'es-PA', 'es-PE', 'es-PH', 'es-PM', 'es-PR', 'es-PY', 'es-SR', 'es-SV', 'es-SX', 'es-TC', 'es-TT', 'es-US', 'es-UY', 'es-VC', 'es-VE', 'es-VG', 'es-VI', 'et', 'et-EE', 'eu', 'eu-ES', 'ewo', 'ewo-CM', 'fa', 'fa-AF', 'fa-IR', 'ff', 'ff-Latn', 'ff-Latn-BF', 'ff-Latn-CM', 'ff-Latn-GH', 'ff-Latn-GM', 'ff-Latn-GN', 'ff-Latn-GW', 'ff-Latn-LR', 'ff-Latn-MR', 'ff-Latn-NE', 'ff-Latn-NG', 'ff-Latn-SL', 'ff-Latn-SN', 'fi', 'fi-FI', 'fil', 'fil-PH', 'fo', 'fo-DK', 'fo-FO', 'fr', 'fr-BE', 'fr-BF', 'fr-BI', 'fr-BJ', 'fr-BL', 'fr-CA', 'fr-CD', 'fr-CF', 'fr-CG', 'fr-CH', 'fr-CI', 'fr-CM', 'fr-DJ', 'fr-DZ', 'fr-FR', 'fr-GA', 'fr-GF', 'fr-GN', 'fr-GP', 'fr-GQ', 'fr-HT', 'fr-KM', 'fr-LU', 'fr-MA', 'fr-MC', 'fr-MF', 'fr-MG', 'fr-ML', 'fr-MQ', 'fr-MR', 'fr-MU', 'fr-NC', 'fr-NE', 'fr-PF', 'fr-PM', 'fr-RE', 'fr-RW', 'fr-SC', 'fr-SN', 'fr-SY', 'fr-TD', 'fr-TG', 'fr-TN', 'fr-VU', 'fr-WF', 'fr-YT', 'fur', 'fur-IT', 'fy', 'fy-NL', 'ga', 'ga-IE', 'gaa', 'gaa-GH', 'gd', 'gd-GB', 'gez', 'gez-ER', 'gez-ET', 'gl', 'gl-ES', 'gn', 'gn-PY', 'gsw', 'gsw-CH', 'gsw-FR', 'gsw-LI', 'gu', 'gu-IN', 'guz', 'guz-KE', 'gv', 'gv-IM', 'ha', 'ha-GH', 'ha-NE', 'ha-NG', 'haw', 'haw-US', 'he', 'he-IL', 'hi', 'hi-IN', 'hi-Latn', 'hr', 'hr-BA', 'hr-HR', 'hsb', 'hsb-DE', 'hu', 'hu-HU', 'hy', 'hy-AM', 'ia', 'ia-001', 'id', 'id-ID', 'ig', 'ig-NG', 'ii', 'ii-CN', 'io', 'io-001', 'is', 'is-IS', 'it', 'it-CH', 'it-IT', 'it-SM', 'it-VA', 'iu', 'iu-CA', 'ja', 'ja-JP', 'jbo', 'jbo-001', 'jgo', 'jgo-CM', 'jmc', 'jmc-TZ', 'jv', 'jv-ID', 'ka', 'ka-GE', 'kab', 'kab-DZ', 'kaj', 'kaj-NG', 'kam', 'kam-KE', 'kcg', 'kcg-NG', 'kde', 'kde-TZ', 'kea', 'kea-CV', 'khq', 'khq-ML', 'ki', 'ki-KE', 'kk', 'kk-KZ', 'kkj', 'kkj-CM', 'kl', 'kl-GL', 'kln', 'kln-KE', 'km', 'km-KH', 'kn', 'kn-IN', 'ko', 'ko-KP', 'ko-KR', 'kok', 'kok-IN', 'kpe', 'kpe-GN', 'kpe-LR', 'ks', 'ks-Arab', 'ks-Arab-IN', 'ks-Aran', 'ks-Aran-IN', 'ks-Deva', 'ks-IN', 'ksb', 'ksb-TZ', 'ksf', 'ksf-CM', 'ksh', 'ksh-DE', 'ku', 'ku-TR', 'kw', 'kw-GB', 'ky', 'ky-KG', 'lag', 'lag-TZ', 'lb', 'lb-LU', 'lg', 'lg-UG', 'lkt', 'lkt-US', 'ln', 'ln-AO', 'ln-CD', 'ln-CF', 'ln-CG', 'lo', 'lo-LA', 'lrc', 'lrc-IQ', 'lrc-IR', 'lt', 'lt-LT', 'lu', 'lu-CD', 'luo', 'luo-KE', 'luy', 'luy-KE', 'lv', 'lv-LV', 'mas', 'mas-KE', 'mas-TZ', 'mer', 'mer-KE', 'mfe', 'mfe-MU', 'mg', 'mg-MG', 'mgh', 'mgh-MZ', 'mgo', 'mgo-CM', 'mi', 'mi-NZ', 'mk', 'mk-MK', 'ml', 'ml-IN', 'mn', 'mn-MN', 'mni', 'mni-Beng', 'mni-Beng-IN', 'mni-Mtei', 'mni-Mtei-IN', 'moh', 'moh-CA', 'mr', 'mr-IN', 'ms', 'ms-Arab', 'ms-Arab-BN', 'ms-Arab-MY', 'ms-BN', 'ms-MY', 'ms-SG', 'mt', 'mt-MT', 'mua', 'mua-CM', 'my', 'my-MM', 'myv', 'myv-RU', 'mzn', 'mzn-IR', 'naq', 'naq-NA', 'nb', 'nb-NO', 'nb-SJ', 'nd', 'nd-ZW', 'nds', 'nds-DE', 'nds-NL', 'ne', 'ne-IN', 'ne-NP', 'nl', 'nl-AW', 'nl-BE', 'nl-BQ', 'nl-CW', 'nl-NL', 'nl-SR', 'nl-SX', 'nmg', 'nmg-CM', 'nn', 'nn-NO', 'nnh', 'nnh-CM', 'nqo', 'nqo-GN', 'nr', 'nr-ZA', 'nso', 'nso-ZA', 'nus', 'nus-SS', 'ny', 'ny-MW', 'nyn', 'nyn-UG', 'oc', 'oc-FR', 'om', 'om-ET', 'om-KE', 'or', 'or-IN', 'os', 'os-GE', 'os-RU', 'pa', 'pa-Arab', 'pa-Arab-PK', 'pa-Aran', 'pa-Aran-PK', 'pa-Guru', 'pa-Guru-IN', 'pl', 'pl-PL', 'ps', 'ps-AF', 'ps-PK', 'pt', 'pt-AO', 'pt-BR', 'pt-CH', 'pt-CV', 'pt-FR', 'pt-GQ', 'pt-GW', 'pt-LU', 'pt-MO', 'pt-MZ', 'pt-PT', 'pt-ST', 'pt-TL', 'qu', 'qu-BO', 'qu-EC', 'qu-PE', 'rm', 'rm-CH', 'rn', 'rn-BI', 'ro', 'ro-MD', 'ro-RO', 'rof', 'rof-TZ', 'ru', 'ru-BY', 'ru-KG', 'ru-KZ', 'ru-MD', 'ru-RU', 'ru-UA', 'rw', 'rw-RW', 'rwk', 'rwk-TZ', 'sa', 'sa-IN', 'sah', 'sah-RU', 'saq', 'saq-KE', 'sat', 'sat-Deva', 'sat-Deva-IN', 'sat-Olck', 'sat-Olck-IN', 'sbp', 'sbp-TZ', 'sc', 'sc-IT', 'scn', 'scn-IT', 'sd', 'sd-Deva', 'sd-PK', 'se', 'se-FI', 'se-NO', 'se-SE', 'seh', 'seh-MZ', 'ses', 'ses-ML', 'sg', 'sg-CF', 'shi', 'shi-Latn', 'shi-Latn-MA', 'shi-Tfng', 'shi-Tfng-MA', 'si', 'si-LK', 'sk', 'sk-SK', 'sl', 'sl-SI', 'smn', 'smn-FI', 'sn', 'sn-ZW', 'so', 'so-DJ', 'so-ET', 'so-KE', 'so-SO', 'sq', 'sq-AL', 'sq-MK', 'sq-XK', 'sr', 'sr-Cyrl', 'sr-Cyrl-BA', 'sr-Cyrl-ME', 'sr-Cyrl-RS', 'sr-Cyrl-XK', 'sr-Latn', 'sr-Latn-BA', 'sr-Latn-ME', 'sr-Latn-RS', 'sr-Latn-XK', 'ss', 'ss-SZ', 'ss-ZA', 'st', 'st-LS', 'st-ZA', 'sv', 'sv-AX', 'sv-FI', 'sv-SE', 'sw', 'sw-CD', 'sw-KE', 'sw-TZ', 'sw-UG', 'syr', 'syr-IQ', 'syr-SY', 'ta', 'ta-IN', 'ta-LK', 'ta-MY', 'ta-SG', 'te', 'te-IN', 'teo', 'teo-KE', 'teo-UG', 'tg', 'tg-TJ', 'th', 'th-TH', 'ti', 'ti-ER', 'ti-ET', 'tig', 'tig-ER', 'tk', 'tk-TM', 'tn', 'tn-BW', 'tn-ZA', 'to', 'to-TO', 'tr', 'tr-CY', 'tr-TR', 'trv', 'trv-TW', 'ts', 'ts-ZA', 'tt', 'tt-RU', 'twq', 'twq-NE', 'tzm', 'tzm-MA', 'ug', 'ug-CN', 'uk', 'uk-UA', 'ur', 'ur-Arab', 'ur-Arab-IN', 'ur-Arab-PK', 'ur-Aran', 'ur-Aran-IN', 'ur-Aran-PK', 'ur-IN', 'ur-PK', 'uz', 'uz-Arab', 'uz-Arab-AF', 'uz-Cyrl', 'uz-Cyrl-UZ', 'uz-Latn', 'uz-Latn-UZ', 'vai', 'vai-Latn', 'vai-Latn-LR', 'vai-Vaii', 'vai-Vaii-LR', 've', 've-ZA', 'vi', 'vi-VN', 'vun', 'vun-TZ', 'wa', 'wa-BE', 'wae', 'wae-CH', 'wal', 'wal-ET', 'wo', 'wo-SN', 'wuu', 'xh', 'xh-ZA', 'xog', 'xog-UG', 'yav', 'yav-CM', 'yi', 'yi-001', 'yo', 'yo-BJ', 'yo-NG', 'yue', 'yue-Hans', 'yue-Hans-CN', 'yue-Hant', 'yue-Hant-HK', 'zgh', 'zgh-MA', 'zh', 'zh-Hans', 'zh-Hans-CN', 'zh-Hans-HK', 'zh-Hans-MO', 'zh-Hans-SG', 'zh-Hant', 'zh-Hant-CN', 'zh-Hant-HK', 'zh-Hant-MO', 'zh-Hant-TW', 'zu', 'zu-ZA')]
    [ValidateNotNull()]
    [string]
    ${Culture},
    
    [Parameter(ParameterSetName = 'ObjectRaw', Mandatory, ValueFromPipeline)]
    [Parameter(ParameterSetName = 'Object', Mandatory, ValueFromPipeline)]
    [AllowEmptyString()]
    [AllowNull()]
    [psobject]
    ${InputObject},
    
    [Parameter(Mandatory, Position = 0)]
    [string[]]
    ${Pattern},
    
    [Parameter(ParameterSetName = 'FileRaw', Mandatory, Position = 1, ValueFromPipelineByPropertyName)]
    [Parameter(ParameterSetName = 'File', Mandatory, Position = 1, ValueFromPipelineByPropertyName)]
    [string[]]
    ${Path},
    
    [Parameter(ParameterSetName = 'LiteralFileRaw', Mandatory, ValueFromPipelineByPropertyName)]
    [Parameter(ParameterSetName = 'LiteralFile', Mandatory, ValueFromPipelineByPropertyName)]
    [Alias('PSPath', 'LP')]
    [string[]]
    ${LiteralPath},
    
    [Parameter(ParameterSetName = 'LiteralFileRaw', Mandatory)]
    [Parameter(ParameterSetName = 'FileRaw', Mandatory)]
    [Parameter(ParameterSetName = 'ObjectRaw', Mandatory)]
    [switch]
    ${Raw},
    
    [switch]
    ${SimpleMatch},
    
    [switch]
    ${CaseSensitive},
    
    [Parameter(ParameterSetName = 'File')]
    [Parameter(ParameterSetName = 'Object')]
    [Parameter(ParameterSetName = 'LiteralFile')]
    [switch]
    ${Quiet},
    
    [switch]
    ${List},
    
    [switch]
    ${NoEmphasis},
    
    [ValidateNotNullOrEmpty()]
    [string[]]
    ${Include},
    
    [ValidateNotNullOrEmpty()]
    [string[]]
    ${Exclude},
    
    [switch]
    ${NotMatch},
    
    [switch]
    ${AllMatches},
    
    [ValidateNotNullOrEmpty()]
    [System.Text.Encoding]
    ${Encoding},
    
    [ValidateRange(0, 2147483647)]
    [ValidateNotNullOrEmpty()]
    [ValidateCount(1, 2)]
    [int[]]
    ${Context})
    
  begin {
    # Ignore parameters that are only supported in v7+
    if ($PSVersionTable.PSVersion.Major -lt 7) {
      ('Culture', 'Raw', 'NoEmphasis').ForEach( {
          if ($PSBoundParameters.ContainsKey($_)) {
            $null = $PSBoundParameters.Remove($_)
            Write-Warning "Ignoring parameter $_, because it is only supported in PowerShell 7.0 or above."
          }
        })
    }
    # Set up the steppable pipeline.
    try {
      $commandToWrap = { Out-String -Stream | Select-String @PSBoundParameters }
      $steppablePipeline = $commandToWrap.GetSteppablePipeline($myInvocation.CommandOrigin)
      $steppablePipeline.Begin($PSCmdlet)
    }
    catch {
      $PSCmdlet.ThrowTerminatingError($_)
    }
  }
    
  process {
    $steppablePipeline.Process($_)
  }
    
  end {
    $steppablePipeline.End()
  }
    
}
like image 2
mklement0 Avatar answered Oct 10 '22 05:10

mklement0