@@ -115,6 +115,23 @@ public static IEnumerable<string> GetDNSServers()
115115 return SettingsManager . Current . DNSLookup_DNSServers . Select ( x => x . Name ) ;
116116 }
117117
118+ /// <summary>
119+ /// Gets the port profiles of the Port Scanner (e.g. "Webserver"), which can be used instead of ports.
120+ /// </summary>
121+ /// <returns>Port profiles.</returns>
122+ public static IEnumerable < PortProfileInfo > GetPortProfiles ( )
123+ {
124+ return SettingsManager . Current . PortScanner_PortProfiles ;
125+ }
126+
127+ /// <summary>
128+ /// Gets the port profile with the name (case-insensitive), or null if there is none.
129+ /// </summary>
130+ private static PortProfileInfo GetPortProfile ( string name )
131+ {
132+ return GetPortProfiles ( ) . FirstOrDefault ( x => string . Equals ( x . Name , name , StringComparison . OrdinalIgnoreCase ) ) ;
133+ }
134+
118135 /// <summary>
119136 /// Gets the translated name of the application (or settings) of a command.
120137 /// </summary>
@@ -148,13 +165,14 @@ public static IEnumerable<ProfileInfo> GetProfiles(RunCommandDefinition command)
148165 /// </summary>
149166 /// <param name="target">Target (e.g. "10.0.0.1").</param>
150167 /// <param name="commands">Available commands.</param>
168+ /// <param name="kind">Kind of the target if it is already known, otherwise it is detected.</param>
151169 /// <returns>Commands with the input to run, in the default order of the kind of the target.</returns>
152170 public static IEnumerable < ( RunCommandDefinition Command , string Text ) > GetCommandsForTarget ( string target ,
153- IReadOnlyList < RunCommandDefinition > commands )
171+ IReadOnlyList < RunCommandDefinition > commands , RunCommandTargetKind ? kind = null )
154172 {
155- var kind = RunCommandTarget . GetKind ( target ) ;
173+ kind ?? = RunCommandTarget . GetKind ( target ) ;
156174
157- if ( ! TargetApplications . TryGetValue ( kind , out var applications ) )
175+ if ( ! TargetApplications . TryGetValue ( kind . Value , out var applications ) )
158176 yield break ;
159177
160178 foreach ( var application in applications )
@@ -210,6 +228,15 @@ public static string TryCreateRequest(RunCommandParseResult result, ProfileInfo
210228 {
211229 request = null ;
212230
231+ // A profile selected in the suggestions is run with its settings, also if its name can't be typed (e.g. it
232+ // starts with a quote, which is parsed as a quoted name).
233+ if ( profile != null && result . Command is { Type : RunCommandType . Application } )
234+ {
235+ request = new ApplicationRequest ( result . Command . Application ) { Profile = profile } ;
236+
237+ return null ;
238+ }
239+
213240 var error = GetParseErrorMessage ( result ) ;
214241
215242 if ( error != null )
@@ -223,6 +250,10 @@ public static string TryCreateRequest(RunCommandParseResult result, ProfileInfo
223250 {
224251 if ( profile == null )
225252 {
253+ // The profiles are not loaded until the (encrypted) profile file is unlocked.
254+ if ( ConfigurationManager . Current . ProfileManagerShowUnlock )
255+ return Strings . UnlockTheProfileFileMessage ;
256+
226257 // The name is compared like it is parsed (without surrounding whitespace and quotes).
227258 var profiles = GetProfiles ( result . Command )
228259 . Where ( x => string . Equals ( x . Name . Trim ( ) . Trim ( '"' ) . Trim ( ) , result . ProfileName ,
@@ -307,6 +338,10 @@ ApplicationName.Traceroute or ApplicationName.PowerShell or ApplicationName.PuTT
307338 if ( error != null )
308339 return error ;
309340
341+ // The Port Scanner needs ports (or a port profile), a new tab has none.
342+ if ( result . Command . Argument == RunCommandArgument . Ports && result . Argument == null )
343+ return Strings . EnterValidPortOrPortRange ;
344+
310345 if ( result . Argument != null )
311346 {
312347 ValidationRule argumentValidator = result . Command . Argument switch
@@ -319,6 +354,8 @@ ApplicationName.Traceroute or ApplicationName.PowerShell or ApplicationName.PuTT
319354 error = result . Command . Argument switch
320355 {
321356 RunCommandArgument . DNSServer => ValidateDNSServer ( result . Argument ) ,
357+ // A port profile (e.g. "Webserver") or ports
358+ RunCommandArgument . Ports when GetPortProfile ( result . Argument ) != null => null ,
322359 RunCommandArgument . Subnet => ValidateSubnetArgument ( result . Target , result . Argument ) ,
323360 _ => Validate ( argumentValidator , result . Argument )
324361 } ;
@@ -409,7 +446,12 @@ private static ApplicationRequest CreateRequest(RunCommandParseResult result)
409446 // Without a type, the DNS lookup uses PTR for IP addresses and its selected type for hosts.
410447 QueryType = result . Type != null ? Enum . Parse < QueryType > ( result . Type , true ) : null
411448 } ,
412- ApplicationName . PortScanner => new PortScannerRequest { Target = result . Target , Ports = result . Argument } ,
449+ // A port profile is used with its ports.
450+ ApplicationName . PortScanner => new PortScannerRequest
451+ {
452+ Target = result . Target ,
453+ Ports = GetPortProfile ( result . Argument ) ? . Ports ?? result . Argument
454+ } ,
413455 ApplicationName . WakeOnLAN => new WakeOnLANRequest { Target = result . Target , Broadcast = result . Argument } ,
414456 ApplicationName . RDAP => new RDAPRequest { Target = result . Target , QueryType = GetRDAPQueryType ( result . Type ) } ,
415457 // The argument is a new subnet mask (Subnetting) or a second subnet (Wide Subnet).
@@ -444,8 +486,12 @@ static RunCommandSyntaxPart Argument(string name) =>
444486 var commands = ApplicationManager . GetNames ( ) . Where ( x => x != ApplicationName . None ) . Select ( name => name switch
445487 {
446488 ApplicationName . IPScanner => Create ( name , [ "ipscan" ] , [ Target ( Strings . IPRange ) ] ) ,
447- ApplicationName . PortScanner => Create ( name , [ "portscan" ] , [ Target ( Strings . Hosts ) , Argument ( Strings . Ports ) ] ,
448- RunCommandArgument . Ports ) ,
489+ ApplicationName . PortScanner => Create ( name , [ "portscan" ] ,
490+ [
491+ Target ( Strings . Hosts ) ,
492+ RunCommandSyntaxPart . Required ( RunCommandSyntaxPartKind . Argument ,
493+ $ "{ Strings . Ports } | { Strings . PortProfile } ")
494+ ] , RunCommandArgument . Ports ) ,
449495 ApplicationName . PingMonitor => Create ( name , [ "ping" ] , [ Target ( Strings . Hosts ) ] ) ,
450496 ApplicationName . Traceroute => Create ( name , [ "trace" , "tracert" ] , [ Target ( Strings . Host ) ] ) ,
451497 ApplicationName . DNSLookup => Create ( name , [ "dns" , "nslookup" ] ,
0 commit comments