Commands/Select-OpenPackage.ps1
|
function Select-OpenPackage { <# .SYNOPSIS Selects Open Package content .DESCRIPTION Selects content from an Open Package using Regular Expressions or XPath .LINK Select-String .LINK Select-Xml #> [Alias('Select-OP','scop', 'scOpenPackage')] [CmdletBinding(DefaultParameterSetName='All')] param( # A list of patterns to match. [Parameter(ParameterSetName='Select-String',ValueFromPipelineByPropertyName)] [PSObject[]] $Pattern, # Indicates that the cmdlet uses a simple match rather than a regular expression match. [Parameter(ParameterSetName='Select-String')] [switch] $SimpleMatch, # Indicates that the cmdlet matches are case-sensitive. By default, pattern matches aren't case-sensitive. [Parameter(ParameterSetName='Select-String')] [switch] $CaseSensitive, <# Indicates that the cmdlet returns a simple response instead of a `[MatchInfo]` object. The returned value is `$true` if the pattern is found or `$null` if the pattern is not found. #> [Parameter(ParameterSetName='Select-String')] [switch] $Quiet, # Only the first instance of matching text is returned from each input file. # This is the most efficient way to retrieve a list of files that have contents matching the regular expression. [Parameter(ParameterSetName='Select-String')] [switch] $List, <# By default, `Select-String` highlights the string that matches the pattern you searched for with the `-Pattern` parameter. The `-NoEmphasis` parameter disables the highlighting. #> [Parameter(ParameterSetName='Select-String')] [switch] $NoEmphasis, <# Includes the specified parts. Enter a wildcard pattern, such as `*.txt` Wildcards are permitted. #> [ValidateNotNullOrEmpty()] [SupportsWildcards()] [string[]] $Include, <# Excludes the specified parts. Enter a wildcard pattern, such as `*.txt` Wildcards are permitted. #> [ValidateNotNullOrEmpty()] [SupportsWildcards()] [string[]] $Exclude, <# Includes the specified content types. Enter a wildcard pattern, such as `text/*` #> [ValidateNotNullOrEmpty()] [SupportsWildcards()] [string[]] $IncludeContentType, <# Excludes the specified content types. Enter a wildcard pattern, such as `text/*` #> [ValidateNotNullOrEmpty()] [SupportsWildcards()] [string[]] $ExcludeContentType, # The `-NotMatch` parameter finds text that doesn't match the specified pattern. [Parameter(ParameterSetName='Select-String')] [switch] $NotMatch, <# Indicates that the cmdlet searches for more than one match in each line of text. Without this parameter, `Select-String` finds only the first match in each line of text. When `Select-String` finds more than one match in a line of text, it still emits only one `[MatchInfo]` object for the line, but the `.Matches` property of the object contains all the matches. #> [Parameter(ParameterSetName='Select-String')] [switch] $AllMatches, <# Captures the specified number of lines before and after the line that matches the pattern. If you enter one number as the value of this parameter, that number determines the number of lines captured before and after the match. If you enter two numbers as the value, the first number determines the number of lines before the match and the second number determines the number of lines after the match. For example, `-Context 2,3`. #> [Parameter(ParameterSetName='Select-String')] [ValidateNotNullOrEmpty()] [ValidateCount(1, 2)] [ValidateRange(0, 2147483647)] [int[]] $Context, <# Causes the cmdlet to output only the matching strings, rather than **MatchInfo** objects. This is the results in behavior that's the most similar to the Unix **grep** or Windows **findstr.exe** commands. #> [Parameter(ParameterSetName='Select-String')] [switch] $Raw, # Specifies an XPath search query. The query language is case-sensitive. [Parameter(Mandatory,ParameterSetName='Select-XML')] [Parameter(ValueFromPipelineByPropertyName)] [PSObject] $XPath, <# Specifies a hash table of the namespaces used in the XML. Use the format`@{<namespaceName> = <namespaceValue>}`. When the XML uses the default namespace, which begins with xmlns, use an arbitrary key for the namespace name. You cannot use xmlns. In the XPath statement, prefix each node name with the namespace name and a colon, such as `//namespaceName:Node`. #> [Parameter(ParameterSetName='Select-XML')] [Parameter(ValueFromPipelineByPropertyName)] [Collections.IDictionary] $Namespace, # One or more Abstract Syntax Tree conditions. # These will select elements in any PowerShell scripts that match the condition. [Parameter(ParameterSetName='Ast', ValueFromPipelineByPropertyName)] [Alias('AstSearch', 'SearchAst')] [ScriptBlock[]] $AstCondition, # The input object. This should be a package. [Parameter(ValueFromPipeline,ValueFromPipelineByPropertyName)] [Alias('Package')] [PSObject] $InputObject ) begin { $selectString = $ExecutionContext.SessionState.InvokeCommand.GetCommand('Select-String','Cmdlet') $selectXml = $ExecutionContext.SessionState.InvokeCommand.GetCommand('Select-Xml','Cmdlet') filter selectOrList { if ($list) { $inputPart } else { $_ } } } process { if ($InputObject -isnot [IO.Packaging.Package]) { return $InputObject } $inputParts = @($InputObject.GetParts()) $inputParts = @( :nextPart foreach ($inputPart in $inputParts) { if ($ExcludeContentType) { foreach ($wildcard in $Exclude) { if ($inputPart.ContentType -like $wildcard) { continue nextPart } } } if ($Exclude) { foreach ($wildcard in $Exclude) { if ($inputPart.Uri -like $wildcard) { continue nextPart } } } if ($include) { $included = $false :included foreach ($wildcard in $include) { if ($inputPart.Uri -like $wildcard) { $included = $true break included } } if (-not $included) { continue nextPart } } if ($IncludeContentType) { $included = $false :included foreach ($wildcard in $include) { if ($inputPart.ContentType -like $wildcard) { $included = $true break included } } if (-not $included) { continue nextPart } } $inputPart } ) :nextPart foreach ($inputPart in $inputParts) { if (-not $Pattern -and -not $XPath -and -not $AstCondition) { $inputPart continue } $inputStream = $inputPart.GetStream() $inputStreamReader = [IO.StreamReader]::new($inputStream) $inputText = $inputStreamReader.ReadToEnd() $inputStreamReader.Close() $inputStreamReader.Dispose() $inputStream.Close() $inputStream.Dispose() $selectParameters = [Ordered]@{} $inputAsXml = $inputText -as [xml] if ($XPath -and $inputAsXml) { $selectParameters.XPath = $XPath if ($namespace) { $selectParameters.Namespace = @{} foreach ($key in $Namespace.Keys) { $selectParameters.Namespace[$key] = $Namespace[$key] } } $inputAsXml | & $selectXml @selectParameters | Add-Member NoteProperty Uri $inputPart.Uri -Force -PassThru | Select-Object Node, Pattern, Uri | . selectOrList } if ($Pattern) { foreach ($key in $PSBoundParameters.Keys) { if ($selectString.Parameters[$key]) { $selectParameters[$key] = $PSBoundParameters[$key] } } $selectParameters.Remove('Include') $selectParameters.Remove('Exclude') Select-String @selectParameters -InputObject $inputText | Add-Member NoteProperty Uri $inputPart.Uri -Force -PassThru | Add-Member NoteProperty Package $InputObject -Force -PassThru | . selectOrList } $inputAsScript = if ($inputPart.Uri -match '\.ps[md]?1$') { try { [scriptblock]::Create($inputText) } catch { $null } } else { '' } if ($AstCondition -and $inputAsScript.Ast.FindAll) { foreach ($searchScript in $AstCondition) { $inputAsScript.Ast.FindAll($searchScript, $true) | Add-Member NoteProperty Uri $inputPart.Uri -Force -PassThru | Add-Member NoteProperty Package $InputObject -Force -PassThru | . selectOrList } } } } } |