Text.ps1
|
# Copyright (c) Microsoft Corporation. # Licensed under the MIT License. filter Use-Parse { <# .SYNOPSIS Parse incoming text to find relevant pieces in it .DESCRIPTION Parses incoming stream of strings and matches each string to a regex pattern. The regex pattern must define regex groups that are used to capture extracted text. The extracted text is stored in output object that is constructed dynamically. Each regex group match would be stored in that object as string property with name defined by $args unbound parameters. If no unbound parameter is specified, the first group match is returned. .PARAMETER Pattern Regex used in matching. Regex groups are used to define significant pieces of text that are extracted from incoming stream. .PARAMETER Args The $args array (the unbound command parameters) contain names of properties that would be used to capture each regex group match. Each property would be populated with corresponding regex group match value in the order of their definition. If no args are passed, the first regex group match value is returned as result. .PARAMETER Enforce Specify this flag if all passed object must match the regex pattern. If mismatch is found, an exception is thrown. By default: not set, all not matching elements would be silently skipped. .EXAMPLE "Info string ABC encoded in text CDE" | parse "string (.+) encoded in text (.+)$" First Second Parses string and extracts object with string properties First = "ABC" and Second = "CDE" .EXAMPLE "line 1", "line 2", "line three" | parse "line (\d+)" Parses incoming array of strings and extracts numeric line numbers. Last line that contain mismatched text is ignored. .EXAMPLE "line 1", "line 2", "line three" | parse "line (\d+)" -Enforce Parses incoming array of strings and extracts numeric line numbers. Last line that contain mismatched text throws an exception. #> param ( [string] $Pattern = $(throw "You must specify the pattern"), [switch] $Enforce ) if( $psitem -notmatch $pattern ) { # Process not matching elements if( $enforce ) { throw "Failed to parse: $($psitem)" } else { return } } if( -not $args ) { return $matches[ 1 ] } $bag = @{} for( $i = 0; $i -lt $args.Count; $i += 1 ) { $bag[$args[$i]] = $matches[$i + 1] } New-Object PsObject -Property $bag | select $args } function Use-Default { <# .SYNOPSIS Define default value if input is null, false or missing .EXAMPLE "test" | default "UNKNOWN" 1,2,2 | default "UNKNOWN" $false | default "UNKNOWN" $null | default "UNKNOWN" $null | select -f 1 | default "null" $head | parse "^([\d-]+\s[\d:]+)z" | foreach{ Get-Date -date $psitem } | default ([datetime]::MaxValue) #> param ( $unsetValue = $null ) begin { $noElements = $true } process { $noElements = $false if( $psitem ) { $psitem } else { $unsetValue } } end { if( $noElements ) { $unsetValue } } } filter Format-Template( [string] $Template = $(throw "Template is mandatory") ) { <# .SYNOPSIS Render text template .DESCRIPTION This function is used to render text from templates and variables that store template-specific information. When {property_name} text is encountered in the template, the function would try to resolve it via: - property of the piped in variables with the same name 'property_name'. - Powershell variable with the same name 'property_name'. Out-String would be used in that case. If multiple objects are piped in, the rendered text would be rendered for each object separately. That allows to conveniently generate text from data. .PARAMETER Template Template string to be used. Any occurrence of {property_name} would be tried to be resolved. If the property can't be resolved, it is left as it is in the template. .EXAMPLE $podXml = $edge | Format-Template @' <Pod name="{PodName}" rack="{RackFloor}" type="{PodType}" location="{City}"> {PowerRendered} {ServerRendered} </Pod> '@ Template used here would use both properties from $edge collection objects (PodName,RackFloor, PodType,City that are specific to a concrete Edge) and from already rendered text (PowerRendered, ServerRendered). .LINK Get-UnresolvedTemplateItem #> $values = $psitem $keys = Get-UnresolvedTemplateItem $template $lastFrameVariables = (Get-PSCallStack)[1].GetFrameVariables() $result = $template foreach( $name in $keys ) { $value = $values.$name if( -not $value ) { $value = if( $lastFrameVariables.ContainsKey($name) ) { $lastFrameVariables[$name].Value } else { Get-Variable $name -ValueOnly -ea Ignore } $value = $value | Out-String | foreach TrimEnd } if( -not $value ) { continue } $result = $result.Replace("{" + $name + "}", $value) } $result } function Get-UnresolvedTemplateItem( [string] $Template = $(throw "Template is mandatory") ) { <# .SYNOPSIS Find template items that were not resolved yet .PARAMETER Template Template string to be used. Any occurrence of {property_name} would be tried to be resolved. If the property can't be resolved, it is left as it is in the template. .EXAMPLE Get-UnresolvedTemplateItem "{templateItem} is an unresolved template item" Finds that 'templateItem' is an unresolved template item. .LINK Format-Template #> [regex]::Matches($template, "\{([^}]+)\}") | foreach{ $psitem.Groups[1].Value } } |