Reputation: 1614
Good Afternoon,
I think I am a little over my head in this particular task. I am trying to create a regex match function to input a command, and split up the command name, parameters, and parameter values.
New-Variable -Name Something -Force Results should be
I have come up with this so far, but it only captures the 1st argument set.
Bonus: Is there any way to make all the matches after the command incrementally named? Say Parameter1, Value1, Parameter2, Value2, etc?
^(?P<Command>[a-zA-Z]+-[a-zA-Z]+)(?: +)((-\S+)(?: |:|=)(.*){0,1})(?: +)
I had no idea the PowerShell parser even existed but this is awesome. This is the code I settled on. Thank you guys for the help!
#Split up the command argument, needed to pull useful information from the command.
New-Variable -force -Name SplitCommand -Value ([System.array]$Null)
$null = [System.Management.Automation.Language.Parser]::ParseInput($Command, [ref]$SplitCommand,[ref]$Null)
$SplitCommand = $SplitCommand.where({-NOT [String]::IsNullOrEmpty($_.text)}).text
Upvotes: 2
Views: 411
Reputation: 174445
Don't use regex for this - use the builtin parser instead:
# Prepare command to parse
$command = 'New-Variable -Name Something -Force'
# Parse command invocation - Parser will return an Abstract Syntax Tree object
$parserErrors = @()
$AST = [System.Management.Automation.Language.Parser]::ParseInput($command, [ref]$null, [ref]$parserErrors)
if($parserErrors){
# error encountered while parsing script
}
else {
# No errors, let's search the AST for the first command invocation
$CommandInvocation = $AST.Find({ $args[0] -is [System.Management.Automation.Language.CommandAst] }, $false)
# Get the string representation of each syntax element in the command invocation
$elements = $CommandInvocation.CommandElements |ForEach-Object ToString
}
Which, with your input (New-Variable -Name Something -Force
), produces the following strings:
PS ~> $elements
New-Variable
-Name
Something
-Force
NOTE: arguments tightly bound to a parameter with :
will be interpreted as a single conjoined syntax element, eg. 'Get-Thing -Name:nameOfThing' will produce only two strings (Get-Thing
and -Name:nameOfThing
) - if you want them split into separate strings, take that into account before converting them to strings:
$elements = $CommandInvocation.CommandElements |ForEach-Object {
if($null -ne $_.Argument){
# tightly bound argument, output both separately
"-$($_.ParameterName)"
$_.Argument
} else {
# just the parameter name, output as-is
$_
}
} |ForEach-Object ToString
Upvotes: 5
Reputation: 437111
To complement Mathias R. Jessen's helpful answer with a streamlined solution, assuming:
you're simply interest in an array of strings representing the command name and its arguments.
that the string represents a syntactically valid command, i.e. that you needn't worry about error handling.
$stringToParse = 'New-Variable -Name Something -Force'
$tokens = $null # Initialize the output variable.
# Parse the string as a PowerShell command.
$null = [System.Management.Automation.Language.Parser]::ParseInput(
$stringToParse,
[ref] $tokens, # will receive a collection of tokens
[ref] $null # would receive a collection of parsing errors; unused here
)
$tokenStrings = $tokens.Text -ne '' # -ne '' ignores the end-of-input token
$tokenStrings
then contains an array of strings with verbatim elements
New-Variable
, -Name
, Something
, -Force
.
See also:
System.Management.Automation.Language.Parser
Upvotes: 2