Skip to content

Instantly share code, notes, and snippets.

@trackd
Created November 2, 2023 13:58
Show Gist options
  • Save trackd/86bf278e99a06231b095462e812326da to your computer and use it in GitHub Desktop.
Save trackd/86bf278e99a06231b095462e812326da to your computer and use it in GitHub Desktop.
function Show-Pipelinecaller {
<#
.SYNOPSIS
Returns an object with the command and resolved command in a pipeline or input line.
@trackd
.PARAMETER Line
the line to parse
.PARAMETER PassThru
just passthrough for objects, not sure how useful that is.
.EXAMPLE
$a = gci | % fullname | gi | Show-PipelineCaller -Verbose
$a | % fullname | gi | Show-PipelineCaller -Verbose -all
.EXAMPLE
could be used to track down the source of a command in a pipeline from a function
Show-Pipelinecaller -Line $MyInvocation.Line
.EXAMPLE
Show-Pipelinecaller -line 'gci -recurse | gi | select -Last 1 | NotAnActualcmd -param stuff -t v'
.EXAMPLE
Show-Pipelinecaller -line '$stevejobs = gci .\apple -recurse | gi | select -first 1' -Verbose
#>
[cmdletbinding()]
param(
[Parameter(Position = 0)]
[string]
$Line,
[Parameter(ValueFromPipeline)]
$InputObject,
[Switch]
$Passthru
)
begin {
Write-Verbose "Command: $($MyInvocation.MyCommand.Name) Param: $($PSBoundParameters.GetEnumerator())"
$i = 1
}
process {
if ($Passthru) {
# not sure how useful this is, will get mixed up with the command names.
$InputObject
}
}
end {
if ($MyInvocation.ExpectingInput) {
$cmdline = $MyInvocation.Line
}
else {
$cmdline = $Line
}
if ($cmdline) {
Write-Verbose $cmdline
$ast = ([System.Management.Automation.Language.Parser]::ParseInput($cmdline, [ref]$null, [ref]$null)).EndBlock.Statements[0]
if ($ast.left) {
# when the pipeline is started by a variable assignment.
Write-Verbose "Pipeline 0 : $($ast.left.extent.text)"
$pipelineElements = $ast.right.PipelineElements
[PSCustomObject]@{
Pipeline = 0
Command = $ast.left.extent.text
Resolved = $ast.operator
params = $ast.right.extent.text
}
}
else {
$pipelineElements = $ast.PipelineElements
}
foreach ($pipeline in $pipelineElements) {
if ($pipeline.commandElements) {
$piped = $pipeline.CommandElements[0].Value
Write-Verbose "Pipeline $i : $piped"
$command = $ExecutionContext.InvokeCommand.GetCommand($piped, 'All')
if (-Not $command) {
# the color is perhaps not best practice, but it is visually distinct.
# $resolved = 'CommandNotFound'
$resolved = "$([char]27)[101mCommandNotFound$([char]27)[0m"
}
elseif ($command.ResolvedCommand) {
Write-Verbose "Resolved alias to $($command.ResolvedCommand.Name)"
$resolved = $command.ResolvedCommand
}
else {
$resolved = $command
}
$param = $pipeline.CommandElements.extent.text -join ' '
}
else {
# when the pipeline is started by a variable.
Write-Verbose "Pipeline $i : $pipeline"
$piped = $resolved = $pipeline
$param = $pipeline.expression.extent.text
}
[PSCustomObject]@{
Pipeline = $i
Command = $piped
Resolved = $resolved
params = $param.replace($piped,'').Trim()
}
$i++
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment