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
}
}
}
CLICK HERE to find out more related problems solutions.