Executables and commanline switches

Ask your Windows PowerShell-related questions, including questions on cmdlet development!
Forum rules
Do not post any licensing information in this forum.

Any code longer than three lines should be added as code using the 'Select Code' dropdown menu or attached as a file.
Locked
User avatar
owinsloe
Posts: 80
Joined: Tue Jul 10, 2012 10:37 am

Executables and commanline switches

Post by owinsloe » Mon Aug 27, 2018 7:05 pm

I just finished reading a contribution from someone querying executable and switch handling and thought I'd post this as it may be useful for others. The code is quite old now so could be improved and consolidated but it shows you one way of handling and I use a copy of this code in most my commandline exe's

When you're inside P.Studio you can uncomment $Commandline for testing. I use the same source code for some scripts where I gen a UI and batch script and can easily determine which-is-which by the presence of $CommandLine.

If you run as a exe then the switches would be myprog.exe -arg1 <value> etc (depending on the arg type.

The



# For testing
#$Commandline = '"-env" "owtest" '
#$CommandLine = '"-env" "xxxUresi" "-in" "xxxTEST" "-s" "xxx1b" "-f" "xxx1a" "-age" "3" '
#$CommandLine = '"-env" "xxxUresi" "-in" "xxxTEST" "-s" "xxx1a" "-age" "3" '

$script:Version='3.0.2.9'
$script:Exe='cnwlogexceptions'

function NewVariable ($Var, $Value)
{
# Use $Var to get fully expanded argument name
[int]$KeyMatch = 0
$CommandArg.keys | ? { $_ -match "^$Var" } | %{ $FullVar = $_; $KeyMatch++ }

if ($KeyMatch -eq 0)
{
write-host "ERROR: -${Var} is not a recognised argument"
[Environment]::Exit(“1”)
}
elseif ($KeyMatch -eq 1)
{
$CommandArg.$FullVar.Assigned = $true
$CommandArg.$FullVar.Value = $Value
}
else
{
write-host "ERROR: -${Var} is ambiguous. Multiple arguments begin with this prefix (ie. $KeyMatch)"
[Environment]::Exit(“1”)
}

$Type = $TypeArgs.$FullVar
# Handle the common integer types
if ($Type -eq 'int32')
{
try { $Value = [convert]::ToInt32($Value, 10) }
catch { }
}
elseif ($Type -eq 'int64')
{
try { $Value = [convert]::ToInt64($Value, 10) }
catch { }
}
elseif ($Type -eq 'decimal')
{
try { $Value = [convert]::ToDecimal($Value) }
catch { }
}

$GetType = (invoke-expression '$Value').gettype().name
if ($Type -eq $GetType)
{
New-Variable -Name $FullVar -Value ($Value -as ([type]$Type)) -Scope global -force
}
else
{
write-host "ERROR: Invalid datatype: argument `"$FullVar`" value `"$Value`" datatype `"$Type`""
[Environment]::Exit(“1”)
}
}
function CommandLine
{
<#
Supported variable types
[string] Fixed-length string of Unicode characters
[char] A Unicode 16-bit character
[byte] An 8-bit unsigned character

[int32] 32-bit signed integer / alias int
[int64] 64-bit signed integer / alias long
[boolean] Boolean True/False value

[decimal] A 128-bit decimal value
[single] Single-precision 32-bit floating point number
[double] Double-precision 64-bit floating point number
[DateTime] Date and Time

[xml] Xml object
[array] An array of values
[hashtable] Hashtable object
#>

# Define variable name & types
$CommandArg = @{ }
# Specify all optional args
$OptionalArgs = @('help','server','age','rundate','frontend','instance')

# Specify the variables and types
$TypeArgs = @{
'help' ='boolean';
'envid' = 'string';
'instance' = 'string';
'frontend' = 'string';
'server'='string';
'age' = 'int32';
'rundate' ='int64';
}

# Define possible arguments and their characteristics
$info = @{ }
foreach ($myArg in $TypeArgs.keys)
{
clear-variable -name $myArg -scope script -erroraction silentlycontinue
$info = @{
"$myArg" = @{ 'Name' = "$myArg"; 'Optional' = $false; Value = '' }
}
# Handle other settings
if ($OptionalArgs -contains "$myArg") { $info.$myarg.Optional = $true }
$CommandArg += $info
}

$myArray = @()
[string]$qString = ''
# Handle all the quotes and strip where needed
$CommandLine -split "\s+" | ?{ $_ } | %{
$String = $_
if ($String -match "^`"(.+?)`"$")
{
# Standard string surrounded by double quotes
$myArray += $matches[1]
}
elseif ($String -match "^`"(.+?)$")
{
# Starts with a double quote but none at the end,
# so string must include spaces. Group following strings until end quote
$Newstring = $matches[1]
}
elseif ($String -match "^(.+?)`"$")
{
# Contains an end double quote so we can now assign $NewString to the array
$myArray += "$NewString " + $matches[1]
}
else
{
# no quotes at all so is part of $NewString
$Newstring += " $String"
}
}

$i = -1
foreach ($Field in $myArray)
{
$i++
if ($Field -eq '/?')
{
$VarResult = NewVariable "Help" $true
}
# If we only have one argument then it will be surrounded by double quotes
# so remove these to be consustent with other arguments when there are more than one
elseif ($Field -match "^-")
{
$Var = $Field -replace "^-(.+?)$", '$1'
# If we are the final element then we must be boolean
# if the next element starts with '-' then we must also be a boolean
if (!$myArray[$i + 1] -or $myArray[$i + 1] -match "^-")
{
$VarResult = NewVariable $Var $true
}
}
else
{
# The previous element should always start with a '-', but check
$PreviousVar = $myArray[$i - 1]
if ($PreviousVar -match "^-(.+?)$")
{
$myName = $matches[1]
$VarResult = NewVariable $myName $Field
}
else
{
# should never be here so die
write-host "ERROR: Corrupt commandline arguments"
[Environment]::Exit("1")
}
}
}

# Assign false to all boolean variables not assigned
foreach ($Name in $TypeArgs.keys | sort | ?{ $TypeArgs.$_ -eq 'boolean' -and !(get-variable -name $_ -valueonly -ea silentlycontinue) })
{
New-Variable -Name $Name -scope global -value $false -force
}

####################################################
# Assign some defaults or perform custom evaluations
# none
####################################################

# Final check to confirm require arguments have been supplied
$Count = 0
foreach ($Name in $CommandArg.keys | ? { $CommandArg.$_.Optional -eq $false -and !$CommandArg.$_.Value -and !$Help })
{
write-host "ERROR: -${Name} is a required argument and has not been supplied"
$Count++
}
if ($Count) { [Environment]::Exit(“1”) }
}


# Other functions

# Call the Coomandline
CommandLine
if ($help)
{
$HelpText=@"
CNWLogExceptions v$script:Version
CNWLogExceptions -e <envid> [-a <days>] [-s <server>] [-r <rundate>] [-instance]
blah blah blah
"@
write-host $Helptext
exit
}

Locked