Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Source/GlobalAssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

[assembly: AssemblyVersion("2026.5.30.0")]
[assembly: AssemblyFileVersion("2026.5.30.0")]
[assembly: AssemblyVersion("2026.7.4.0")]
[assembly: AssemblyFileVersion("2026.7.4.0")]
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@
<value>iexplore.exe</value>
</data>
<data name="ExampleCustomCommandVariableHostname" xml:space="preserve">
<value>https://$$HOSTNAME$$/</value>
<value>https://{{Hostname}}/</value>
</data>
<data name="InternetExplorer" xml:space="preserve">
<value>Internet Explorer</value>
Expand Down
50 changes: 37 additions & 13 deletions Source/NETworkManager.Localization/Resources/Strings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 12 additions & 6 deletions Source/NETworkManager.Localization/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,18 @@
<data name="Description" xml:space="preserve">
<value>Description</value>
</data>
<data name="Placeholder" xml:space="preserve">
<value>Placeholder</value>
</data>
<data name="HelpMessage_CustomCommandFilePath" xml:space="preserve">
<value>Path to the file or executable to run. The following placeholders can be used:</value>
</data>
<data name="HelpMessage_CustomCommandArguments" xml:space="preserve">
<value>Arguments passed to the file or executable. The following placeholders can be used:</value>
</data>
<data name="HelpMessage_ProfileHostPlaceholder" xml:space="preserve">
<value>The following placeholder can be used:</value>
</data>
<data name="DHCPEnabled" xml:space="preserve">
<value>DHCP enabled</value>
</data>
Expand Down Expand Up @@ -2244,12 +2256,6 @@ is disabled!</value>
<data name="DeleteCustomCommandMessage" xml:space="preserve">
<value>The selected custom command will be deleted permanently.</value>
</data>
<data name="HelpMessage_CustomCommandVariables" xml:space="preserve">
<value>The following variables are available:

$$ipaddress$$ --&gt; IP adresse
$$hostname$$ --&gt; Hostname</value>
</data>
<data name="Restart" xml:space="preserve">
<value>Restart</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ public static List<CustomCommandInfo> GetDefaultList()
{
return new List<CustomCommandInfo>
{
new(Guid.NewGuid(), "Edge", "cmd.exe", @"/c start microsoft-edge:http://$$ipaddress$$/"),
new(Guid.NewGuid(), "Edge", "cmd.exe", @"/c start microsoft-edge:http://{{IPAddress}}/"),
new(Guid.NewGuid(), "Edge (https)", "cmd.exe",
@"/c start microsoft-edge:https://$$ipaddress$$/"),
new(Guid.NewGuid(), "Windows Explorer (c$)", "explorer.exe", @"\\$$ipaddress$$\c$")
@"/c start microsoft-edge:https://{{IPAddress}}/"),
new(Guid.NewGuid(), "Windows Explorer (c$)", "explorer.exe", @"\\{{IPAddress}}\c$")
};
}
}
13 changes: 8 additions & 5 deletions Source/NETworkManager.Profiles/Application/PowerShell.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using NETworkManager.Models.PowerShell;
using NETworkManager.Settings;
using NETworkManager.Utilities;

namespace NETworkManager.Profiles.Application;

Expand All @@ -20,11 +21,13 @@ public static PowerShellSessionInfo CreateSessionInfo(ProfileInfo profile)
: group.PowerShell_OverrideCommand
? group.PowerShell_Command
: SettingsManager.Current.PowerShell_Command,
AdditionalCommandLine = profile.PowerShell_OverrideAdditionalCommandLine
? profile.PowerShell_AdditionalCommandLine
: group.PowerShell_OverrideAdditionalCommandLine
? group.PowerShell_AdditionalCommandLine
: SettingsManager.Current.PowerShell_AdditionalCommandLine,
AdditionalCommandLine = PlaceholderHelper.Resolve(
profile.PowerShell_OverrideAdditionalCommandLine
? profile.PowerShell_AdditionalCommandLine
: group.PowerShell_OverrideAdditionalCommandLine
? group.PowerShell_AdditionalCommandLine
: SettingsManager.Current.PowerShell_AdditionalCommandLine,
(PlaceholderHelper.Host, profile.Host)),
ExecutionPolicy = profile.PowerShell_OverrideExecutionPolicy
? profile.PowerShell_ExecutionPolicy
: group.PowerShell_OverrideExecutionPolicy
Expand Down
13 changes: 8 additions & 5 deletions Source/NETworkManager.Profiles/Application/PuTTY.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using NETworkManager.Models.PuTTY;
using NETworkManager.Settings;
using NETworkManager.Utilities;

namespace NETworkManager.Profiles.Application;

Expand Down Expand Up @@ -55,11 +56,13 @@ public static PuTTYSessionInfo CreateSessionInfo(ProfileInfo profile)
: group.PuTTY_OverrideLogFileName
? group.PuTTY_LogFileName
: SettingsManager.Current.PuTTY_LogFileName,
AdditionalCommandLine = profile.PuTTY_OverrideAdditionalCommandLine
? profile.PuTTY_AdditionalCommandLine
: group.PuTTY_OverrideAdditionalCommandLine
? group.PuTTY_AdditionalCommandLine
: SettingsManager.Current.PuTTY_AdditionalCommandLine
AdditionalCommandLine = PlaceholderHelper.Resolve(
profile.PuTTY_OverrideAdditionalCommandLine
? profile.PuTTY_AdditionalCommandLine
: group.PuTTY_OverrideAdditionalCommandLine
? group.PuTTY_AdditionalCommandLine
: SettingsManager.Current.PuTTY_AdditionalCommandLine,
(PlaceholderHelper.Host, profile.Host))
};
}
}
3 changes: 2 additions & 1 deletion Source/NETworkManager.Profiles/Application/WebConsole.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using NETworkManager.Models.WebConsole;
using NETworkManager.Utilities;

namespace NETworkManager.Profiles.Application;

Expand All @@ -8,7 +9,7 @@ public static WebConsoleSessionInfo CreateSessionInfo(ProfileInfo profileInfo)
{
var info = new WebConsoleSessionInfo
{
Url = profileInfo.WebConsole_Url
Url = PlaceholderHelper.Resolve(profileInfo.WebConsole_Url, (PlaceholderHelper.Host, profileInfo.Host))
};

return info;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@
<ItemGroup>
<ProjectReference Include="..\NETworkManager.Models\NETworkManager.Models.csproj" />
<ProjectReference Include="..\NETworkManager.Settings\NETworkManager.Settings.csproj" />
<ProjectReference Include="..\NETworkManager.Utilities\NETworkManager.Utilities.csproj" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion Source/NETworkManager.Profiles/ProfileInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ public ProfileInfo(ProfileInfo profile)
public int TigerVNC_Port { get; set; } = GlobalStaticConfiguration.TigerVNC_DefaultVNCPort;

public bool WebConsole_Enabled { get; set; }
public string WebConsole_Url { get; set; }
public string WebConsole_Url { get; set; } = "https://{{Host}}";

public bool SNMP_Enabled { get; set; }
public bool SNMP_InheritHost { get; set; } = true;
Expand Down
31 changes: 31 additions & 0 deletions Source/NETworkManager.Settings/SettingsManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Xml.Serialization;

namespace NETworkManager.Settings;
Expand Down Expand Up @@ -698,6 +699,36 @@ private static void UpgradeToLatest(Version version)

Current.General_ApplicationList[index] = neighborTableEntry;
}

// IP Scanner - Custom commands
Log.Info("Migrating IP Scanner custom command placeholder syntax from \"$$var$$\" to \"{{Var}}\"...");

foreach (var customCommand in Current.IPScanner_CustomCommands)
{
var filePath = customCommand.FilePath;

if (!string.IsNullOrEmpty(filePath))
{
filePath = Regex.Replace(filePath, "\\$\\$ipaddress\\$\\$", "{{IPAddress}}", RegexOptions.IgnoreCase);
filePath = Regex.Replace(filePath, "\\$\\$hostname\\$\\$", "{{Hostname}}", RegexOptions.IgnoreCase);
}

var arguments = customCommand.Arguments;

if (!string.IsNullOrEmpty(arguments))
{
arguments = Regex.Replace(arguments, "\\$\\$ipaddress\\$\\$", "{{IPAddress}}", RegexOptions.IgnoreCase);
arguments = Regex.Replace(arguments, "\\$\\$hostname\\$\\$", "{{Hostname}}", RegexOptions.IgnoreCase);
}

if (filePath == customCommand.FilePath && arguments == customCommand.Arguments)
continue;

Log.Info($"Migrated custom command \"{customCommand.Name}\"...");

customCommand.FilePath = filePath;
customCommand.Arguments = arguments;
}
}
#endregion
}
53 changes: 53 additions & 0 deletions Source/NETworkManager.Utilities/PlaceholderHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System.Text.RegularExpressions;

namespace NETworkManager.Utilities;

/// <summary>
/// Helper class to resolve <c>{{name}}</c> placeholders in a string.
/// </summary>
public static class PlaceholderHelper
{
/// <summary>
/// Placeholder name for the host (e.g. of a profile).
/// </summary>
public const string Host = "host";

/// <summary>
/// Placeholder name for a hostname.
/// </summary>
public const string Hostname = "hostname";

/// <summary>
/// Placeholder name for an IP address.
/// </summary>
public const string IPAddress = "ipaddress";

/// <summary>
/// Replaces a <c>{{name}}</c> placeholder (case-insensitive) with the given value.
/// </summary>
/// <param name="input">Input string that may contain the placeholder.</param>
/// <param name="name">Name of the placeholder, without the surrounding braces (e.g. <c>"hostname"</c>).</param>
/// <param name="value">Value to insert in place of the placeholder.</param>
/// <returns>The input with the placeholder resolved.</returns>
public static string Replace(string input, string name, string value)
{
return string.IsNullOrEmpty(input)
? input
: Regex.Replace(input, $"\\{{\\{{{Regex.Escape(name)}\\}}\\}}", value ?? string.Empty,
RegexOptions.IgnoreCase);
}

/// <summary>
/// Replaces multiple <c>{{name}}</c> placeholders (case-insensitive) with the given values.
/// </summary>
/// <param name="input">Input string that may contain the placeholders.</param>
/// <param name="placeholders">Placeholder name/value pairs to resolve, e.g. <c>(PlaceholderHelper.Host, "10.0.0.1")</c>.</param>
/// <returns>The input with all placeholders resolved.</returns>
public static string Resolve(string input, params (string name, string value)[] placeholders)
{
foreach (var (name, value) in placeholders)
input = Replace(input, name, value);

return input;
}
}
25 changes: 25 additions & 0 deletions Source/NETworkManager.Validators/WebConsoleProfileUrlValidator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using System.Globalization;
using System.Windows.Controls;
using NETworkManager.Localization.Resources;
using NETworkManager.Utilities;

namespace NETworkManager.Validators;

/// <summary>
/// Validates the WebConsole URL field on a profile, which may contain the <c>{{Host}}</c> placeholder.
/// </summary>
public class WebConsoleProfileUrlValidator : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
// Substitute the {{Host}} placeholder with a dummy host so the structural
// URL validation (scheme, format) still applies, without rejecting the placeholder itself.
var input = PlaceholderHelper.Replace(value as string ?? "", PlaceholderHelper.Host, "placeholder-host");

return Uri.TryCreate(input, UriKind.Absolute, out var uriResult) &&
(uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps)
? ValidationResult.ValidResult
: new ValidationResult(false, Strings.EnterValidWebsiteUri);
}
}
13 changes: 6 additions & 7 deletions Source/NETworkManager/ViewModels/IPScannerViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
Expand Down Expand Up @@ -581,15 +580,15 @@ private async Task CustomCommand(object guid)
var hostname = !string.IsNullOrEmpty(SelectedResult.Hostname) ? SelectedResult.Hostname.TrimEnd('.') : "";
var ipAddress = SelectedResult.PingInfo.IPAddress.ToString();

info.FilePath = Regex.Replace(info.FilePath, "\\$\\$hostname\\$\\$", hostname, RegexOptions.IgnoreCase);
info.FilePath = Regex.Replace(info.FilePath, "\\$\\$ipaddress\\$\\$", ipAddress, RegexOptions.IgnoreCase);
info.FilePath = PlaceholderHelper.Resolve(info.FilePath,
(PlaceholderHelper.Hostname, hostname),
(PlaceholderHelper.IPAddress, ipAddress));

if (!string.IsNullOrEmpty(info.Arguments))
{
info.Arguments = Regex.Replace(info.Arguments, "\\$\\$hostname\\$\\$", hostname,
RegexOptions.IgnoreCase);
info.Arguments = Regex.Replace(info.Arguments, "\\$\\$ipaddress\\$\\$", ipAddress,
RegexOptions.IgnoreCase);
info.Arguments = PlaceholderHelper.Resolve(info.Arguments,
(PlaceholderHelper.Hostname, hostname),
(PlaceholderHelper.IPAddress, ipAddress));
}

try
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ private static ObservableCollection<ImportApplicationToggleItem> BuildApplicatio
new ImportApplicationToggleItem(ProfileName.PowerShell, true),
new ImportApplicationToggleItem(ProfileName.PuTTY),
new ImportApplicationToggleItem(ProfileName.TigerVNC),
new ImportApplicationToggleItem(ProfileName.WebConsole),
new ImportApplicationToggleItem(ProfileName.SNMP),
new ImportApplicationToggleItem(ProfileName.Whois),
new ImportApplicationToggleItem(ProfileName.IPGeolocation)
Expand Down Expand Up @@ -251,6 +252,9 @@ private static void ApplyToolDefaults(ProfileInfo profile, ProfileName tool)
profile.TigerVNC_Enabled = true;
profile.TigerVNC_Host = profile.Host;
break;
case ProfileName.WebConsole:
profile.WebConsole_Enabled = true;
break;
case ProfileName.SNMP:
profile.SNMP_Enabled = true;
profile.SNMP_Host = profile.Host;
Expand Down
3 changes: 2 additions & 1 deletion Source/NETworkManager/ViewModels/PowerShellHostViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,8 @@ private Task Connect(string host = null)
EnableRemoteConsole = instance.EnableRemoteConsole,
Host = instance.Host,
Command = instance.Command,
AdditionalCommandLine = instance.AdditionalCommandLine,
AdditionalCommandLine = PlaceholderHelper.Resolve(instance.AdditionalCommandLine,
(PlaceholderHelper.Host, instance.Host)),
ExecutionPolicy = instance.ExecutionPolicy
};

Expand Down
Loading