Handling commandline arguments in VB.NET (or really anything) can be tricky. I came across the following class the other day while looking for a drop-in solution to a RAD I was developing.

Here’s what my usage shows for my application, thanks to the .NET class.

portscan.exe

portscan 0.9.2 by Rich Kreider

Usage: portscan -h <host> -s <startport> -e <endport> -f -d -t <timeoutms>

Options:
        -h      Host.  IP address or hostname.
        -s      Start port.  Begin scan at the specified port.
        -e      End port.  End scan at the specified port (max 65535).
        -f      Fast scan.  Scan without a timeout.  May be unreliable.
        -t      Timeout.  Timeout in ms to confirm port open (not used with -f)
        -p      Single port.  Scan single port.  Ignores -e and -s.
Examples:
        Normal Scan:
                portscan -h 192.168.1.50
        Normal Scan Custom Port Range:
                portscan -h 192.168.1.50 -s 1 -e 1024
        Fast Scan All Ports:
                portscan -h 192.168.1.50 -f
        Normal Scan Single Port:
                portscan -h 192.168.1.50 -p 80

InputArguments.vb

Public Class InputArguments
#Region "fields & properties"
    Public Const DEFAULT_KEY_LEADING_PATTERN As String = "-"

    Protected _parsedArguments As New Dictionary(Of String, String)(StringComparer.OrdinalIgnoreCase)
    Protected ReadOnly _keyLeadingPattern As String

    Default Public Property Item(key As String) As String
        Get
            Return GetValue(key)
        End Get
        Set(ByVal value As String)
            If key IsNot Nothing Then
                _parsedArguments(key) = value
            End If
        End Set
    End Property
    Public ReadOnly Property KeyLeadingPattern() As String
        Get
            Return _keyLeadingPattern
        End Get
    End Property
#End Region

#Region "public methods"
    Public Sub New(args() As String, pkeyLeadingPattern As String)
        _keyLeadingPattern = If(Not String.IsNullOrEmpty(pkeyLeadingPattern), pkeyLeadingPattern, DEFAULT_KEY_LEADING_PATTERN)

        If args IsNot Nothing AndAlso args.Length > 0 Then
            Parse(args)
        End If
    End Sub
    Public Sub New(args() As String)
        Me.New(args, Nothing)
    End Sub

    Public Function Contains(key As String) As Boolean
        Dim adjustedKey As String = Nothing
        Return ContainsKey(key, adjustedKey)
    End Function

    Public Overridable Function GetPeeledKey(key As String) As String
        Return If(IsKey(key), key.Substring(_keyLeadingPattern.Length), key)
    End Function
    Public Overridable Function GetDecoratedKey(ByVal key As String) As String
        Return If(Not IsKey(key), (_keyLeadingPattern & key), key)
    End Function
    Public Overridable Function IsKey(str As String) As Boolean
        Return str.StartsWith(_keyLeadingPattern)
    End Function
#End Region

#Region "internal methods"
    Protected Overridable Sub Parse(args() As String)
        For index As Integer = 0 To args.Length - 1
            If args(index) Is Nothing Then
                Continue For
            End If

            Dim key As String = Nothing
            Dim val As String = Nothing

            If IsKey(args(index)) Then
                key = args(index)

                If index + 1 < args.Length AndAlso Not IsKey(args(index + 1)) Then
                    val = args(index + 1)
                    index += 1
                End If
            Else
                val = args(index)
            End If

            ' adjustment
            If key Is Nothing Then
                key = val
                val = Nothing
            End If
            _parsedArguments(key) = val
        Next
    End Sub

    Protected Overridable Function GetValue(key As String) As String
        Dim adjustedKey As String = Nothing
        If ContainsKey(key, adjustedKey) Then
            Return _parsedArguments(adjustedKey)
        End If

        Return Nothing
    End Function

    Protected Overridable Function ContainsKey(ByVal key As String, <Runtime.InteropServices.Out()> ByRef adjustedKey As String) As Boolean
        adjustedKey = key

        If _parsedArguments.ContainsKey(key) Then
            Return True
        End If

        If IsKey(key) Then
            Dim peeledKey As String = GetPeeledKey(key)
            If _parsedArguments.ContainsKey(peeledKey) Then
                adjustedKey = peeledKey
                Return True
            End If
            Return False
        End If

        Dim decoratedKey As String = GetDecoratedKey(key)
        If _parsedArguments.ContainsKey(decoratedKey) Then
            adjustedKey = decoratedKey
            Return True
        End If
        Return False
    End Function
#End Region
End Class

To make use of the class, I have the following code sample.

Module Module1

Public ReadOnly Property CommandLineArguments As String()
        Get
            Return Environment.GetCommandLineArgs
        End Get
End Property

Dim host as String

Sub Main() {
    Dim arguments As New InputArguments(CommandLineArguments)

    If arguments.Contains("-h") Then
        host = arguments.Item("-h")
    End If
}

End Module

Supplying portscan.exe -h 127.0.0.1 results in the host variable being assigned the commandline argument value of 127.0.0.1.