Splitting command lines into command and arguments

January 8, 2017 at 9:29 am Leave a comment

Having been inspired by a PowerShell.com PowerTip of the day that looked at a function that would do this

http://s1403.t.en25.com/e/es.aspx?s=1403&e=166808&elq=1882a23c7eeb4ef0aae82b42771499bc

I thought that I would expand the concept to write it as a cmdlet that would take pipeline input.  The initial part of the utility worked well for the results of Get-Process which has a property called CommandLine, but not with service objects.  When I piped the Win32_Service objects into a Select-Object to produce a property called CommandLine I found that there were several instances where the PathName references executable under the Program Files directories without enclosing them in quotation marks so I added a function to process the line and add the quote marks on the basis of the executable being a .exe file.  The catch is that the current version will put a quotation mark after each .exe so if this occurs in the arguments, there may be some spurious quotation marks.  There is a switch to skip the processing of the command line.

<#
.Synopsis
Get-CommandLine takes an object that has a parameter
called CommandLine and breaks out the command
element and the arguments.
.DESCRIPTION
The utility creates an object that contains the
initial commandline and the command and arguments
on their own. An attempt will be made to process
the command line to deal with a case, such as can occur
with services, where the executable is in a program files
directory but does not enclose it in quotation marks.
.PARAMETER CommandLine
CommandLine is the string to be processed. Input can come from
the pipeline so long as the object has a property called CommandLine.
.PARAMETER IncludeOriginalCommandLine
IncludeOriginalCommandLine is a switch to tell the cmdlet to included
the value of the CammandLine in the output.
.PARAMETER SkipCommandLineProcessing
If this switch is included the utility will not attempt to parse the
command line and add quotation marks. If this switch is used, it is
advisabel to also use the IncludeOriginalCommandLine switch to be
able to check the full syntax of the command line.
.EXAMPLE
Get-WmiObject -Class Win32_Process | Get-CommandLine | Out-GridView
.EXAMPLE
Get-CommandLine -CommandLine ‘”notepad.exe” c:\test’
.EXAMPLE
Get-WmiObject -Class Win32_Process | Get-CommandLine -IncludeOriginalCommandLine
.EXAMPLE
gwmi Win32_Service | Select @{n=”CommandLine”;e={$PSItem.PathName}} | Get-CommandLine -IncludeOriginalCommandLine | Out-GridView
#>
function Get-CommandLine
{
[CmdletBinding()]
[OutputType([int])]
Param
(
# Param1 help description
[Parameter(ValueFromPipelineByPropertyName=$true,
Position=0)]
[String]$CommandLine,
[Switch]$IncludeOriginalCommandLine,
[Switch]$SkipCommandLineProcessing
)

 

Begin
{
}
Process
{
if (-not [string]::IsNullorEmpty($CommandLine))
{
$originalCommandLine = $CommandLine
function Process-CommandLine
{
Param
(
[string]$CommandLineToProcess,
[string]$BaseDirectory
)

if ($CommandLineToProcess.Substring(0,$BaseDirectory.Length + 1) -eq ($BaseDirectory + “\”))
{
$CommandLineToProcess = “`”” + $BaseDirectory + $CommandLine.Substring($BaseDirectory.Length).Replace(“.exe”,”.exe`” “)
}
return $CommandLineToProcess
}
if (-not $SkipCommandLineProcessing)
{
# processing cases where references are made to the program directories without quotation marks and
# based on the assumption that the command referenced is a .exe.

$baseDirectories = @()
$baseDirectories += ${env:ProgramFiles(x86)}
$baseDirectories += $env:ProgramFiles
$baseDirectories += $env:CommonProgramFiles
$baseDirectories += ${env:CommonProgramFiles(x86)}
$baseDirectories += $env:ProgramW6432
$baseDirectories += $env:CommonProgramW6432
foreach ($bd in $baseDirectories)
{
if ($CommandLine.Length -gt $bd.Length)
{
if ($CommandLine.Substring(0,($bd.Length + 1)) -eq ($bd + “\”))
{
$CommandLine = Process-CommandLine $CommandLine $bd
}
}
}
}

$cmdObject = New-Object PSObject -Property @{
Command = “”
Argument = “”
}
if ($IncludeOriginalCommandLine)
{
$cmdObject | Add-Member -Name CommandLine -MemberType NoteProperty -Value “”
}
$firstChar = $CommandLine.SubString(0,1)
$commandString = “”
switch ($firstChar)
{
‘”‘ {$commandString = $CommandLine.Split(‘”‘)[1]}
“`'” {$commandString = $CommandLine.Split(“`'”)[1]}
Default {$commandString = $CommandLine.Split(” “)[0]}
}
if ($IncludeOriginalCommandLine)
{
$cmdObject.CommandLine = $originalCommandLine
}
$cmdObject.Command = $commandString

if ($firstChar -gt “a”)
{
$cmdObject.Argument = $CommandLine.Substring($commandString.Length)
}
else
{
$cmdObject.Argument = $CommandLine.Substring($commandString.Length+2)
}

Write-Output $cmdObject
}
}
End
{
}

}

 

 

 

Advertisements

Entry filed under: PowerShell.

Personalising PowerShell Commands, or what seemed like a good idea in Redmond isn’t necessarily the best option for me! Converting PowerShell Scripts to HTML for Documentation

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Trackback this post  |  Subscribe to the comments via RSS Feed


Calendar

January 2017
M T W T F S S
« Nov   Feb »
 1
2345678
9101112131415
16171819202122
23242526272829
3031  

Most Recent Posts


%d bloggers like this: