mirror of https://github.com/winsw/winsw
parent
f5b44b958f
commit
a6ba41681d
|
@ -25,11 +25,6 @@ strategy:
|
||||||
Release:
|
Release:
|
||||||
BuildConfiguration: Release
|
BuildConfiguration: Release
|
||||||
steps:
|
steps:
|
||||||
- task: UseDotNet@2
|
|
||||||
displayName: Install .NET SDK
|
|
||||||
inputs:
|
|
||||||
packageType: sdk
|
|
||||||
version: 6.x
|
|
||||||
- task: DotNetCoreCLI@2
|
- task: DotNetCoreCLI@2
|
||||||
displayName: Build
|
displayName: Build
|
||||||
inputs:
|
inputs:
|
||||||
|
@ -37,9 +32,9 @@ steps:
|
||||||
projects: src\WinSW.sln
|
projects: src\WinSW.sln
|
||||||
arguments: -c $(BuildConfiguration) -p:Version=$(BuildVersion)
|
arguments: -c $(BuildConfiguration) -p:Version=$(BuildVersion)
|
||||||
- script: |
|
- script: |
|
||||||
dotnet publish src\WinSW\WinSW.csproj -c $(BuildConfiguration) -f net6.0-windows -r win-x64 -p:Version=$(BuildVersion)
|
dotnet publish src\WinSW\WinSW.csproj -c $(BuildConfiguration) -f net7.0-windows -r win-x64 --sc -p:Version=$(BuildVersion)
|
||||||
dotnet publish src\WinSW\WinSW.csproj -c $(BuildConfiguration) -f net6.0-windows -r win-x86 -p:Version=$(BuildVersion)
|
dotnet publish src\WinSW\WinSW.csproj -c $(BuildConfiguration) -f net7.0-windows -r win-x86 --sc -p:Version=$(BuildVersion)
|
||||||
dotnet publish src\WinSW\WinSW.csproj -c $(BuildConfiguration) -f net6.0-windows -r win-arm64 -p:Version=$(BuildVersion)
|
dotnet publish src\WinSW\WinSW.csproj -c $(BuildConfiguration) -f net7.0-windows -r win-arm64 --sc -p:Version=$(BuildVersion)
|
||||||
displayName: Build
|
displayName: Build
|
||||||
- task: DotNetCoreCLI@2
|
- task: DotNetCoreCLI@2
|
||||||
displayName: Test
|
displayName: Test
|
||||||
|
@ -73,7 +68,7 @@ steps:
|
||||||
|
|
||||||
- publish: artifacts\publish\WinSW-arm64.exe
|
- publish: artifacts\publish\WinSW-arm64.exe
|
||||||
artifact: WinSW-arm64.exe_$(BuildConfiguration)
|
artifact: WinSW-arm64.exe_$(BuildConfiguration)
|
||||||
displayName: Publish .NET arm64 .exe
|
displayName: Publish .NET Arm64 .exe
|
||||||
|
|
||||||
- publish: $(Build.ArtifactStagingDirectory)\WinSW.$(BuildVersion).nupkg
|
- publish: $(Build.ArtifactStagingDirectory)\WinSW.$(BuildVersion).nupkg
|
||||||
artifact: WinSW.nupkg_$(BuildConfiguration)
|
artifact: WinSW.nupkg_$(BuildConfiguration)
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
using System.Runtime.CompilerServices;
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
[assembly: AssemblyMetadata("IsTrimmable", "True")]
|
||||||
[assembly: InternalsVisibleTo("WinSW")]
|
[assembly: InternalsVisibleTo("WinSW")]
|
||||||
[assembly: InternalsVisibleTo("WinSW.Tests")]
|
[assembly: InternalsVisibleTo("WinSW.Tests")]
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net461;net6.0-windows</TargetFrameworks>
|
<TargetFrameworks>net461;net7.0-windows</TargetFrameworks>
|
||||||
<LangVersion>preview</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -15,13 +15,13 @@
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0-windows'">
|
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0-windows'">
|
||||||
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||||
<PackageReference Include="System.Security.AccessControl" Version="6.0.0" />
|
<PackageReference Include="System.Security.AccessControl" Version="6.0.0" />
|
||||||
<PackageReference Include="System.ServiceProcess.ServiceController" Version="5.0.0" />
|
<PackageReference Include="System.ServiceProcess.ServiceController" Version="7.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' != 'net6.0-windows'">
|
<ItemGroup Condition="'$(TargetFramework)' != 'net7.0-windows'">
|
||||||
<PackageReference Include="System.Memory" Version="4.5.5" />
|
<PackageReference Include="System.Memory" Version="4.5.5" />
|
||||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||||
<Reference Include="System.ServiceProcess" />
|
<Reference Include="System.ServiceProcess" />
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net461;net6.0-windows</TargetFrameworks>
|
<TargetFrameworks>net461;net7.0-windows</TargetFrameworks>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
|
@ -17,13 +17,18 @@ namespace WinSW.Tasks
|
||||||
{
|
{
|
||||||
using var module = ModuleDefinition.ReadModule(this.Path, new() { ReadWrite = true, ReadSymbols = true });
|
using var module = ModuleDefinition.ReadModule(this.Path, new() { ReadWrite = true, ReadSymbols = true });
|
||||||
|
|
||||||
|
foreach (var t in module.CustomAttributeTypes())
|
||||||
|
{
|
||||||
|
this.WalkType(t);
|
||||||
|
}
|
||||||
|
|
||||||
this.WalkType(module.EntryPoint.DeclaringType);
|
this.WalkType(module.EntryPoint.DeclaringType);
|
||||||
|
|
||||||
var types = module.Types;
|
var types = module.Types;
|
||||||
for (int i = types.Count - 1; i >= 0; i--)
|
for (int i = types.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
var type = types[i];
|
var type = types[i];
|
||||||
if (type.FullName.Contains("WinSW.Plugins"))
|
if (type.FullName.StartsWith("WinSW.Plugins"))
|
||||||
{
|
{
|
||||||
this.WalkType(type);
|
this.WalkType(type);
|
||||||
}
|
}
|
||||||
|
@ -64,6 +69,10 @@ namespace WinSW.Tasks
|
||||||
this.WalkType(genericArg);
|
this.WalkType(genericArg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (typeRef is IModifierType modifierType)
|
||||||
|
{
|
||||||
|
this.WalkType(modifierType.ModifierType);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="17.2.0" />
|
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="17.4.0" />
|
||||||
<PackageReference Include="Mono.Cecil" Version="0.11.4" />
|
<PackageReference Include="Mono.Cecil" Version="0.11.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ namespace WinSW.Tests
|
||||||
|
|
||||||
var result = Helper.ErrorTest(new[] { commandName });
|
var result = Helper.ErrorTest(new[] { commandName });
|
||||||
|
|
||||||
Assert.Equal($"Unrecognized command or argument '{commandName}'\r\n\r\n", result.Error);
|
Assert.Equal($"Unrecognized command or argument '{commandName}'.\r\n\r\n", result.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net471;net6.0-windows</TargetFrameworks>
|
<TargetFrameworks>net471;net7.0-windows</TargetFrameworks>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@ -12,15 +12,15 @@
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.Diagnostics.Runtime" Version="2.0.226801" />
|
<PackageReference Include="Microsoft.Diagnostics.Runtime" Version="2.0.226801" />
|
||||||
<PackageReference Include="Microsoft.Diagnostics.Runtime.Utilities" Version="2.0.0-rc.20303.3" />
|
<PackageReference Include="Microsoft.Diagnostics.Runtime.Utilities" Version="2.0.0-rc.20303.3" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
|
||||||
<PackageReference Include="xunit" Version="2.4.1" />
|
<PackageReference Include="xunit" Version="2.4.2" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' != 'net6.0-windows'">
|
<ItemGroup Condition="'$(TargetFramework)' != 'net7.0-windows'">
|
||||||
<PackageReference Include="System.Reflection.Metadata" Version="5.0.0" />
|
<PackageReference Include="System.Reflection.Metadata" Version="5.0.0" />
|
||||||
<Reference Include="System.ServiceProcess" />
|
<Reference Include="System.ServiceProcess" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -39,11 +39,11 @@
|
||||||
|
|
||||||
<Target Name="Copy" BeforeTargets="AfterBuild">
|
<Target Name="Copy" BeforeTargets="AfterBuild">
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0-windows'">
|
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0-windows'">
|
||||||
<_FilesToCopy Include="$(ArtifactsBinDir)WinSW\$(Configuration)\net6.0-windows\WinSW.runtimeconfig*.json" />
|
<_FilesToCopy Include="$(ArtifactsBinDir)WinSW\$(Configuration)\net7.0-windows\WinSW.runtimeconfig*.json" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' != 'net6.0-windows'">
|
<ItemGroup Condition="'$(TargetFramework)' != 'net7.0-windows'">
|
||||||
<_FilesToCopy Include="$(ArtifactsBinDir)WinSW\$(Configuration)\net461\System.ValueTuple.dll" />
|
<_FilesToCopy Include="$(ArtifactsBinDir)WinSW\$(Configuration)\net461\System.ValueTuple.dll" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
using System.Runtime.CompilerServices;
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
[assembly: AssemblyMetadata("IsTrimmable", "True")]
|
||||||
[assembly: InternalsVisibleTo("WinSW.Tests")]
|
[assembly: InternalsVisibleTo("WinSW.Tests")]
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
using System;
|
||||||
|
using System.CommandLine;
|
||||||
|
using System.CommandLine.Invocation;
|
||||||
|
|
||||||
|
namespace WinSW
|
||||||
|
{
|
||||||
|
internal static class CommandExtensions
|
||||||
|
{
|
||||||
|
internal static void SetHandler<T>(this Command command, Action<T, InvocationContext> handle, Argument<T> symbol)
|
||||||
|
{
|
||||||
|
command.SetHandler(context =>
|
||||||
|
{
|
||||||
|
var value = context.ParseResult.GetValueForArgument(symbol);
|
||||||
|
handle(value!, context);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void SetHandler<T1, T2, T3>(this Command command, Action<T1, T2, T3, InvocationContext> handle, Argument<T1> symbol1, Option<T2> symbol2, Option<T3> symbol3)
|
||||||
|
{
|
||||||
|
command.SetHandler(context =>
|
||||||
|
{
|
||||||
|
var value1 = context.ParseResult.GetValueForArgument(symbol1);
|
||||||
|
var value2 = context.ParseResult.GetValueForOption(symbol2);
|
||||||
|
var value3 = context.ParseResult.GetValueForOption(symbol3);
|
||||||
|
handle(value1!, value2!, value3!, context);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void SetHandler<T1, T2, T3, T4>(this Command command, Action<T1, T2, T3, T4, InvocationContext> handle, Argument<T1> symbol1, Option<T2> symbol2, Option<T3> symbol3, Option<T4> symbol4)
|
||||||
|
{
|
||||||
|
command.SetHandler(context =>
|
||||||
|
{
|
||||||
|
var value1 = context.ParseResult.GetValueForArgument(symbol1);
|
||||||
|
var value2 = context.ParseResult.GetValueForOption(symbol2);
|
||||||
|
var value3 = context.ParseResult.GetValueForOption(symbol3);
|
||||||
|
var value4 = context.ParseResult.GetValueForOption(symbol4);
|
||||||
|
handle(value1!, value2!, value3!, value4!, context);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,6 @@ using System.Reflection;
|
||||||
using System.Security.AccessControl;
|
using System.Security.AccessControl;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.ServiceProcess;
|
using System.ServiceProcess;
|
||||||
using System.Threading;
|
|
||||||
using log4net;
|
using log4net;
|
||||||
using log4net.Appender;
|
using log4net.Appender;
|
||||||
using log4net.Config;
|
using log4net.Config;
|
||||||
|
@ -107,9 +106,272 @@ namespace WinSW
|
||||||
elevated = IsProcessElevated();
|
elevated = IsProcessElevated();
|
||||||
}
|
}
|
||||||
|
|
||||||
var root = new RootCommand("A wrapper binary that can be used to host executables as Windows services. https://github.com/winsw/winsw")
|
var serviceConfig = new Argument<string?>("path-to-config")
|
||||||
{
|
{
|
||||||
Handler = CommandHandler.Create((string? pathToConfig) =>
|
Arity = ArgumentArity.ZeroOrOne,
|
||||||
|
IsHidden = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
var root = new RootCommand("A wrapper binary that can be used to host executables as Windows services. https://github.com/winsw/winsw");
|
||||||
|
|
||||||
|
using (var identity = WindowsIdentity.GetCurrent())
|
||||||
|
{
|
||||||
|
var principal = new WindowsPrincipal(identity);
|
||||||
|
if (principal.IsInRole(new SecurityIdentifier(WellKnownSidType.ServiceSid, null)) ||
|
||||||
|
principal.IsInRole(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null)) ||
|
||||||
|
principal.IsInRole(new SecurityIdentifier(WellKnownSidType.LocalServiceSid, null)) ||
|
||||||
|
principal.IsInRole(new SecurityIdentifier(WellKnownSidType.NetworkServiceSid, null)))
|
||||||
|
{
|
||||||
|
root.Add(serviceConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root.SetHandler(Run, serviceConfig);
|
||||||
|
|
||||||
|
var config = new Argument<string?>("path-to-config", "The path to the configuration file.")
|
||||||
|
{
|
||||||
|
Arity = ArgumentArity.ZeroOrOne,
|
||||||
|
};
|
||||||
|
|
||||||
|
var noElevate = new Option<bool>("--no-elevate", "Doesn't automatically trigger a UAC prompt.");
|
||||||
|
|
||||||
|
{
|
||||||
|
var username = new Option<string?>(new[] { "--username", "--user" }, "Specifies the user name of the service account.");
|
||||||
|
var password = new Option<string?>(new[] { "--password", "--pass" }, "Specifies the password of the service account.");
|
||||||
|
|
||||||
|
var install = new Command("install", "Installs the service.")
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
noElevate,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
};
|
||||||
|
install.SetHandler(Install, config, noElevate, username, password);
|
||||||
|
|
||||||
|
root.Add(install);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var uninstall = new Command("uninstall", "Uninstalls the service.")
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
noElevate,
|
||||||
|
};
|
||||||
|
uninstall.SetHandler(Uninstall, config, noElevate);
|
||||||
|
|
||||||
|
root.Add(uninstall);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var noWait = new Option<bool>("--no-wait", "Doesn't wait for the service to actually start.");
|
||||||
|
|
||||||
|
var start = new Command("start", "Starts the service.")
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
noElevate,
|
||||||
|
noWait,
|
||||||
|
};
|
||||||
|
start.SetHandler(Start, config, noElevate, noWait);
|
||||||
|
|
||||||
|
root.Add(start);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var noWait = new Option<bool>("--no-wait", "Doesn't wait for the service to actually stop.");
|
||||||
|
var force = new Option<bool>("--force", "Stops the service even if it has started dependent services.");
|
||||||
|
|
||||||
|
var stop = new Command("stop", "Stops the service.")
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
noElevate,
|
||||||
|
noWait,
|
||||||
|
force,
|
||||||
|
};
|
||||||
|
stop.SetHandler(Stop, config, noElevate, noWait, force);
|
||||||
|
|
||||||
|
root.Add(stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var force = new Option<bool>("--force", "Restarts the service even if it has started dependent services.");
|
||||||
|
|
||||||
|
var restart = new Command("restart", "Stops and then starts the service.")
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
noElevate,
|
||||||
|
force,
|
||||||
|
};
|
||||||
|
restart.SetHandler(Restart, config, noElevate, force);
|
||||||
|
|
||||||
|
root.Add(restart);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var restartSelf = new Command("restart!", "self-restart (can be called from child processes)")
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
};
|
||||||
|
restartSelf.SetHandler(RestartSelf, config);
|
||||||
|
|
||||||
|
root.Add(restartSelf);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var status = new Command("status", "Checks the status of the service.")
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
};
|
||||||
|
status.SetHandler(Status, config);
|
||||||
|
|
||||||
|
root.Add(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var refresh = new Command("refresh", "Refreshes the service properties without reinstallation.")
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
noElevate,
|
||||||
|
};
|
||||||
|
refresh.SetHandler(Refresh, config, noElevate);
|
||||||
|
|
||||||
|
root.Add(refresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var output = new Option<string>(new[] { "--output", "-o" })
|
||||||
|
{
|
||||||
|
IsRequired = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
var manufacturer = new Option<string>("--manufacturer")
|
||||||
|
{
|
||||||
|
IsRequired = true,
|
||||||
|
};
|
||||||
|
manufacturer.AddValidator(result =>
|
||||||
|
{
|
||||||
|
const int minLength = 12;
|
||||||
|
const int maxLength = 15;
|
||||||
|
|
||||||
|
string token = result.Tokens.Single().Value;
|
||||||
|
int length = token.Length;
|
||||||
|
result.ErrorMessage =
|
||||||
|
length < minLength ? $"The length of argument '{token}' must be greater than or equal to {minLength}." :
|
||||||
|
length > maxLength ? $"The length of argument '{token}' must be less than or equal to {maxLength}." :
|
||||||
|
null;
|
||||||
|
});
|
||||||
|
|
||||||
|
var customize = new Command("customize", "Customizes the wrapper executable.")
|
||||||
|
{
|
||||||
|
output,
|
||||||
|
manufacturer,
|
||||||
|
};
|
||||||
|
customize.SetHandler(Customize, output, manufacturer);
|
||||||
|
|
||||||
|
root.Add(customize);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var dev = new Command("dev", "Experimental commands.");
|
||||||
|
|
||||||
|
root.Add(dev);
|
||||||
|
|
||||||
|
{
|
||||||
|
var all = new Option<bool>(new[] { "--all", "-a" });
|
||||||
|
|
||||||
|
var ps = new Command("ps", "Draws the process tree associated with the service.")
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
all,
|
||||||
|
};
|
||||||
|
ps.SetHandler(DevPs, config, all);
|
||||||
|
|
||||||
|
dev.Add(ps);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var kill = new Command("kill", "Terminates the service if it has stopped responding.")
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
noElevate,
|
||||||
|
};
|
||||||
|
kill.SetHandler(DevKill, config, noElevate);
|
||||||
|
|
||||||
|
dev.Add(kill);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var list = new Command("list", "Lists services managed by the current executable.");
|
||||||
|
list.SetHandler(DevList);
|
||||||
|
|
||||||
|
dev.Add(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CommandLineBuilder(root)
|
||||||
|
.UseVersionOption()
|
||||||
|
.UseHelp()
|
||||||
|
.RegisterWithDotnetSuggest()
|
||||||
|
.UseTypoCorrections()
|
||||||
|
.UseParseErrorReporting()
|
||||||
|
.UseExceptionHandler(TestExceptionHandler ?? OnException)
|
||||||
|
.CancelOnProcessTermination()
|
||||||
|
.Build()
|
||||||
|
.Invoke(args);
|
||||||
|
|
||||||
|
static void OnException(Exception exception, InvocationContext context)
|
||||||
|
{
|
||||||
|
switch (exception)
|
||||||
|
{
|
||||||
|
case InvalidDataException e:
|
||||||
|
{
|
||||||
|
string message = "The configuration file could not be loaded. " + e.Message;
|
||||||
|
Log.Fatal(message, e);
|
||||||
|
context.ExitCode = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OperationCanceledException e:
|
||||||
|
{
|
||||||
|
Debug.Assert(e.CancellationToken == context.GetCancellationToken());
|
||||||
|
Log.Fatal(e.Message);
|
||||||
|
context.ExitCode = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CommandException e:
|
||||||
|
{
|
||||||
|
string message = e.Message;
|
||||||
|
Log.Fatal(message);
|
||||||
|
context.ExitCode = e.InnerException is Win32Exception inner ? inner.NativeErrorCode : -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case InvalidOperationException e when e.InnerException is Win32Exception inner:
|
||||||
|
{
|
||||||
|
string message = e.Message;
|
||||||
|
Log.Fatal(message);
|
||||||
|
context.ExitCode = inner.NativeErrorCode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Win32Exception e:
|
||||||
|
{
|
||||||
|
string message = e.Message;
|
||||||
|
Log.Fatal(message, e);
|
||||||
|
context.ExitCode = e.NativeErrorCode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
Log.Fatal("Unhandled exception", exception);
|
||||||
|
context.ExitCode = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Run(string? pathToConfig)
|
||||||
{
|
{
|
||||||
XmlServiceConfig config = null!;
|
XmlServiceConfig config = null!;
|
||||||
try
|
try
|
||||||
|
@ -134,270 +396,6 @@ namespace WinSW
|
||||||
{
|
{
|
||||||
// handled in OnStart
|
// handled in OnStart
|
||||||
}
|
}
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
using (var identity = WindowsIdentity.GetCurrent())
|
|
||||||
{
|
|
||||||
var principal = new WindowsPrincipal(identity);
|
|
||||||
if (principal.IsInRole(new SecurityIdentifier(WellKnownSidType.ServiceSid, null)) ||
|
|
||||||
principal.IsInRole(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null)) ||
|
|
||||||
principal.IsInRole(new SecurityIdentifier(WellKnownSidType.LocalServiceSid, null)) ||
|
|
||||||
principal.IsInRole(new SecurityIdentifier(WellKnownSidType.NetworkServiceSid, null)))
|
|
||||||
{
|
|
||||||
root.Add(new Argument<string?>("path-to-config")
|
|
||||||
{
|
|
||||||
Arity = ArgumentArity.ZeroOrOne,
|
|
||||||
IsHidden = true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var config = new Argument<string?>("path-to-config", "The path to the configuration file.")
|
|
||||||
{
|
|
||||||
Arity = ArgumentArity.ZeroOrOne,
|
|
||||||
};
|
|
||||||
|
|
||||||
var noElevate = new Option("--no-elevate", "Doesn't automatically trigger a UAC prompt.");
|
|
||||||
|
|
||||||
{
|
|
||||||
var install = new Command("install", "Installs the service.")
|
|
||||||
{
|
|
||||||
Handler = CommandHandler.Create<string?, bool, string?, string?>(Install),
|
|
||||||
};
|
|
||||||
|
|
||||||
install.Add(config);
|
|
||||||
install.Add(noElevate);
|
|
||||||
install.Add(new Option<string?>(new[] { "--username", "--user" }, "Specifies the user name of the service account."));
|
|
||||||
install.Add(new Option<string?>(new[] { "--password", "--pass" }, "Specifies the password of the service account."));
|
|
||||||
|
|
||||||
root.Add(install);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var uninstall = new Command("uninstall", "Uninstalls the service.")
|
|
||||||
{
|
|
||||||
Handler = CommandHandler.Create<string?, bool>(Uninstall),
|
|
||||||
};
|
|
||||||
|
|
||||||
uninstall.Add(config);
|
|
||||||
uninstall.Add(noElevate);
|
|
||||||
|
|
||||||
root.Add(uninstall);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var start = new Command("start", "Starts the service.")
|
|
||||||
{
|
|
||||||
Handler = CommandHandler.Create<string?, bool, bool, CancellationToken>(Start),
|
|
||||||
};
|
|
||||||
|
|
||||||
start.Add(config);
|
|
||||||
start.Add(noElevate);
|
|
||||||
start.Add(new Option("--no-wait", "Doesn't wait for the service to actually start."));
|
|
||||||
|
|
||||||
root.Add(start);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var stop = new Command("stop", "Stops the service.")
|
|
||||||
{
|
|
||||||
Handler = CommandHandler.Create<string?, bool, bool, bool, CancellationToken>(Stop),
|
|
||||||
};
|
|
||||||
|
|
||||||
stop.Add(config);
|
|
||||||
stop.Add(noElevate);
|
|
||||||
stop.Add(new Option("--no-wait", "Doesn't wait for the service to actually stop."));
|
|
||||||
stop.Add(new Option("--force", "Stops the service even if it has started dependent services."));
|
|
||||||
|
|
||||||
root.Add(stop);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var restart = new Command("restart", "Stops and then starts the service.")
|
|
||||||
{
|
|
||||||
Handler = CommandHandler.Create<string?, bool, bool, CancellationToken>(Restart),
|
|
||||||
};
|
|
||||||
|
|
||||||
restart.Add(config);
|
|
||||||
restart.Add(noElevate);
|
|
||||||
restart.Add(new Option("--force", "Restarts the service even if it has started dependent services."));
|
|
||||||
|
|
||||||
root.Add(restart);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var restartSelf = new Command("restart!", "self-restart (can be called from child processes)")
|
|
||||||
{
|
|
||||||
Handler = CommandHandler.Create<string?>(RestartSelf),
|
|
||||||
};
|
|
||||||
|
|
||||||
restartSelf.Add(config);
|
|
||||||
|
|
||||||
root.Add(restartSelf);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var status = new Command("status", "Checks the status of the service.")
|
|
||||||
{
|
|
||||||
Handler = CommandHandler.Create<string?>(Status),
|
|
||||||
};
|
|
||||||
|
|
||||||
status.Add(config);
|
|
||||||
|
|
||||||
root.Add(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var refresh = new Command("refresh", "Refreshes the service properties without reinstallation.")
|
|
||||||
{
|
|
||||||
Handler = CommandHandler.Create<string?, bool>(Refresh),
|
|
||||||
};
|
|
||||||
|
|
||||||
refresh.Add(config);
|
|
||||||
refresh.Add(noElevate);
|
|
||||||
|
|
||||||
root.Add(refresh);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var customize = new Command("customize", "Customizes the wrapper executable.")
|
|
||||||
{
|
|
||||||
Handler = CommandHandler.Create<string, string>(Customize),
|
|
||||||
};
|
|
||||||
|
|
||||||
customize.Add(new Option<string>(new[] { "--output", "-o" })
|
|
||||||
{
|
|
||||||
Required = true,
|
|
||||||
});
|
|
||||||
|
|
||||||
var manufacturer = new Option<string>("--manufacturer")
|
|
||||||
{
|
|
||||||
Required = true,
|
|
||||||
};
|
|
||||||
manufacturer.Argument.AddValidator(argument =>
|
|
||||||
{
|
|
||||||
const int minLength = 12;
|
|
||||||
const int maxLength = 15;
|
|
||||||
|
|
||||||
string token = argument.Tokens.Single().Value;
|
|
||||||
int length = token.Length;
|
|
||||||
return
|
|
||||||
length < minLength ? $"The length of argument '{token}' must be greater than or equal to {minLength}." :
|
|
||||||
length > maxLength ? $"The length of argument '{token}' must be less than or equal to {maxLength}." :
|
|
||||||
null;
|
|
||||||
});
|
|
||||||
|
|
||||||
customize.Add(manufacturer);
|
|
||||||
|
|
||||||
root.Add(customize);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var dev = new Command("dev", "Experimental commands.");
|
|
||||||
|
|
||||||
root.Add(dev);
|
|
||||||
|
|
||||||
{
|
|
||||||
var ps = new Command("ps", "Draws the process tree associated with the service.")
|
|
||||||
{
|
|
||||||
Handler = CommandHandler.Create<string?, bool>(DevPs),
|
|
||||||
};
|
|
||||||
|
|
||||||
ps.Add(config);
|
|
||||||
|
|
||||||
ps.Add(new Option(new[] { "--all", "-a" }));
|
|
||||||
|
|
||||||
dev.Add(ps);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var kill = new Command("kill", "Terminates the service if it has stopped responding.")
|
|
||||||
{
|
|
||||||
Handler = CommandHandler.Create<string?, bool>(DevKill),
|
|
||||||
};
|
|
||||||
|
|
||||||
kill.Add(config);
|
|
||||||
kill.Add(noElevate);
|
|
||||||
|
|
||||||
dev.Add(kill);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var list = new Command("list", "Lists services managed by the current executable.")
|
|
||||||
{
|
|
||||||
Handler = CommandHandler.Create(DevList),
|
|
||||||
};
|
|
||||||
|
|
||||||
dev.Add(list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new CommandLineBuilder(root)
|
|
||||||
.UseVersionOption()
|
|
||||||
.UseHelp()
|
|
||||||
.RegisterWithDotnetSuggest()
|
|
||||||
.UseTypoCorrections()
|
|
||||||
.UseParseErrorReporting()
|
|
||||||
.UseExceptionHandler(TestExceptionHandler ?? OnException)
|
|
||||||
.CancelOnProcessTermination()
|
|
||||||
.Build()
|
|
||||||
.Invoke(args);
|
|
||||||
|
|
||||||
static void OnException(Exception exception, InvocationContext context)
|
|
||||||
{
|
|
||||||
Debug.Assert(exception is TargetInvocationException);
|
|
||||||
Debug.Assert(exception.InnerException != null);
|
|
||||||
exception = exception.InnerException!;
|
|
||||||
switch (exception)
|
|
||||||
{
|
|
||||||
case InvalidDataException e:
|
|
||||||
{
|
|
||||||
string message = "The configuration file could not be loaded. " + e.Message;
|
|
||||||
Log.Fatal(message, e);
|
|
||||||
context.ResultCode = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case OperationCanceledException e:
|
|
||||||
{
|
|
||||||
Debug.Assert(e.CancellationToken == context.GetCancellationToken());
|
|
||||||
Log.Fatal(e.Message);
|
|
||||||
context.ResultCode = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case CommandException e:
|
|
||||||
{
|
|
||||||
string message = e.Message;
|
|
||||||
Log.Fatal(message);
|
|
||||||
context.ResultCode = e.InnerException is Win32Exception inner ? inner.NativeErrorCode : -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case InvalidOperationException e when e.InnerException is Win32Exception inner:
|
|
||||||
{
|
|
||||||
string message = e.Message;
|
|
||||||
Log.Fatal(message);
|
|
||||||
context.ResultCode = inner.NativeErrorCode;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Win32Exception e:
|
|
||||||
{
|
|
||||||
string message = e.Message;
|
|
||||||
Log.Fatal(message, e);
|
|
||||||
context.ResultCode = e.NativeErrorCode;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
Log.Fatal("Unhandled exception", exception);
|
|
||||||
context.ResultCode = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Install(string? pathToConfig, bool noElevate, string? username, string? password)
|
void Install(string? pathToConfig, bool noElevate, string? username, string? password)
|
||||||
|
@ -557,7 +555,7 @@ namespace WinSW
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Start(string? pathToConfig, bool noElevate, bool noWait, CancellationToken ct)
|
void Start(string? pathToConfig, bool noElevate, bool noWait, InvocationContext context)
|
||||||
{
|
{
|
||||||
var config = LoadConfigAndInitLoggers(pathToConfig, true);
|
var config = LoadConfigAndInitLoggers(pathToConfig, true);
|
||||||
|
|
||||||
|
@ -580,6 +578,7 @@ namespace WinSW
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var ct = context.GetCancellationToken();
|
||||||
svc.WaitForStatus(ServiceControllerStatus.Running, ServiceControllerStatus.StartPending, ct);
|
svc.WaitForStatus(ServiceControllerStatus.Running, ServiceControllerStatus.StartPending, ct);
|
||||||
}
|
}
|
||||||
catch (TimeoutException)
|
catch (TimeoutException)
|
||||||
|
@ -602,7 +601,7 @@ namespace WinSW
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stop(string? pathToConfig, bool noElevate, bool noWait, bool force, CancellationToken ct)
|
void Stop(string? pathToConfig, bool noElevate, bool noWait, bool force, InvocationContext context)
|
||||||
{
|
{
|
||||||
var config = LoadConfigAndInitLoggers(pathToConfig, true);
|
var config = LoadConfigAndInitLoggers(pathToConfig, true);
|
||||||
|
|
||||||
|
@ -633,6 +632,7 @@ namespace WinSW
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var ct = context.GetCancellationToken();
|
||||||
svc.WaitForStatus(ServiceControllerStatus.Stopped, ServiceControllerStatus.StopPending, ct);
|
svc.WaitForStatus(ServiceControllerStatus.Stopped, ServiceControllerStatus.StopPending, ct);
|
||||||
}
|
}
|
||||||
catch (TimeoutException)
|
catch (TimeoutException)
|
||||||
|
@ -655,7 +655,7 @@ namespace WinSW
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Restart(string? pathToConfig, bool noElevate, bool force, CancellationToken ct)
|
void Restart(string? pathToConfig, bool noElevate, bool force, InvocationContext context)
|
||||||
{
|
{
|
||||||
var config = LoadConfigAndInitLoggers(pathToConfig, true);
|
var config = LoadConfigAndInitLoggers(pathToConfig, true);
|
||||||
|
|
||||||
|
@ -688,6 +688,7 @@ namespace WinSW
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var ct = context.GetCancellationToken();
|
||||||
svc.WaitForStatus(ServiceControllerStatus.Stopped, ServiceControllerStatus.StopPending, ct);
|
svc.WaitForStatus(ServiceControllerStatus.Stopped, ServiceControllerStatus.StopPending, ct);
|
||||||
}
|
}
|
||||||
catch (TimeoutException)
|
catch (TimeoutException)
|
||||||
|
@ -710,6 +711,7 @@ namespace WinSW
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var ct = context.GetCancellationToken();
|
||||||
svc.WaitForStatus(ServiceControllerStatus.Running, ServiceControllerStatus.StartPending, ct);
|
svc.WaitForStatus(ServiceControllerStatus.Running, ServiceControllerStatus.StartPending, ct);
|
||||||
}
|
}
|
||||||
catch (TimeoutException)
|
catch (TimeoutException)
|
||||||
|
@ -763,7 +765,7 @@ namespace WinSW
|
||||||
_ = HandleApis.CloseHandle(processInfo.ThreadHandle);
|
_ = HandleApis.CloseHandle(processInfo.ThreadHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Status(string? pathToConfig)
|
static void Status(string? pathToConfig, InvocationContext context)
|
||||||
{
|
{
|
||||||
var config = LoadConfigAndInitLoggers(pathToConfig, true);
|
var config = LoadConfigAndInitLoggers(pathToConfig, true);
|
||||||
|
|
||||||
|
@ -781,7 +783,7 @@ namespace WinSW
|
||||||
_ => "Inactive (stopped)"
|
_ => "Inactive (stopped)"
|
||||||
});
|
});
|
||||||
|
|
||||||
return svc.Status switch
|
context.ExitCode = svc.Status switch
|
||||||
{
|
{
|
||||||
ServiceControllerStatus.Stopped => 0,
|
ServiceControllerStatus.Stopped => 0,
|
||||||
_ => 1
|
_ => 1
|
||||||
|
@ -791,7 +793,7 @@ namespace WinSW
|
||||||
when (e.InnerException is Win32Exception inner && inner.NativeErrorCode == Errors.ERROR_SERVICE_DOES_NOT_EXIST)
|
when (e.InnerException is Win32Exception inner && inner.NativeErrorCode == Errors.ERROR_SERVICE_DOES_NOT_EXIST)
|
||||||
{
|
{
|
||||||
Console.WriteLine("NonExistent");
|
Console.WriteLine("NonExistent");
|
||||||
return Errors.ERROR_SERVICE_DOES_NOT_EXIST;
|
context.ExitCode = Errors.ERROR_SERVICE_DOES_NOT_EXIST;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,10 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFrameworks>net461;net6.0-windows</TargetFrameworks>
|
<TargetFrameworks>net461;net7.0-windows</TargetFrameworks>
|
||||||
<LangVersion>preview</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<PublishTrimmed>true</PublishTrimmed>
|
|
||||||
|
|
||||||
<AssemblyTitle>Windows Service Wrapper</AssemblyTitle>
|
<AssemblyTitle>Windows Service Wrapper</AssemblyTitle>
|
||||||
<Description>Allows arbitrary process to run as a Windows service by wrapping it.</Description>
|
<Description>Allows arbitrary process to run as a Windows service by wrapping it.</Description>
|
||||||
|
@ -15,19 +14,27 @@
|
||||||
<Copyright>Copyright (c) 2008-2020 Kohsuke Kawaguchi, Sun Microsystems, Inc., CloudBees, Inc., Oleg Nenashev and other contributors</Copyright>
|
<Copyright>Copyright (c) 2008-2020 Kohsuke Kawaguchi, Sun Microsystems, Inc., CloudBees, Inc., Oleg Nenashev and other contributors</Copyright>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(TargetFramework)' == 'net6.0-windows' AND '$(RuntimeIdentifier)' != ''">
|
<PropertyGroup>
|
||||||
|
<PublishTrimmed>true</PublishTrimmed>
|
||||||
|
<TrimMode>partial</TrimMode>
|
||||||
|
<DebuggerSupport>false</DebuggerSupport>
|
||||||
|
<NullabilityInfoContextSupport>false</NullabilityInfoContextSupport>
|
||||||
|
<_AggressiveAttributeTrimming>true</_AggressiveAttributeTrimming>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(TargetFramework)' == 'net7.0-windows' AND '$(RuntimeIdentifier)' != ''">
|
||||||
<PublishSingleFile>true</PublishSingleFile>
|
<PublishSingleFile>true</PublishSingleFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(TargetFramework)' != 'net6.0-windows'">
|
<PropertyGroup Condition="'$(TargetFramework)' != 'net7.0-windows'">
|
||||||
<ILMergeVersion>3.0.41</ILMergeVersion>
|
<ILMergeVersion>3.0.41</ILMergeVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20303.1" />
|
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' != 'net6.0-windows'">
|
<ItemGroup Condition="'$(TargetFramework)' != 'net7.0-windows'">
|
||||||
<PackageReference Include="ilmerge" Version="$(ILMergeVersion)" />
|
<PackageReference Include="ilmerge" Version="$(ILMergeVersion)" />
|
||||||
<Reference Include="System.ServiceProcess" />
|
<Reference Include="System.ServiceProcess" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -37,11 +44,11 @@
|
||||||
<ProjectReference Include="..\WinSW.Plugins\WinSW.Plugins.csproj" />
|
<ProjectReference Include="..\WinSW.Plugins\WinSW.Plugins.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' != 'net6.0-windows'">
|
<ItemGroup Condition="'$(TargetFramework)' != 'net7.0-windows'">
|
||||||
<ProjectReference Include="..\WinSW.Tasks\WinSW.Tasks.csproj" ReferenceOutputAssembly="false" />
|
<ProjectReference Include="..\WinSW.Tasks\WinSW.Tasks.csproj" ReferenceOutputAssembly="false" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PublishCoreExe" AfterTargets="Publish" Condition="'$(TargetFramework)' == 'net6.0-windows'">
|
<Target Name="PublishCoreExe" AfterTargets="Publish" Condition="'$(TargetFramework)' == 'net7.0-windows'">
|
||||||
|
|
||||||
<MakeDir Directories="$(ArtifactsPublishDir)" />
|
<MakeDir Directories="$(ArtifactsPublishDir)" />
|
||||||
<Copy SourceFiles="$(PublishDir)$(TargetName).exe" DestinationFiles="$(ArtifactsPublishDir)WinSW-$(PlatformTarget).exe" />
|
<Copy SourceFiles="$(PublishDir)$(TargetName).exe" DestinationFiles="$(ArtifactsPublishDir)WinSW-$(PlatformTarget).exe" />
|
||||||
|
@ -49,7 +56,7 @@
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<!-- Merge plugins and other DLLs into the executable -->
|
<!-- Merge plugins and other DLLs into the executable -->
|
||||||
<Target Name="Merge" BeforeTargets="AfterBuild" Condition="'$(TargetFramework)' != 'net6.0-windows'">
|
<Target Name="Merge" BeforeTargets="AfterBuild" Condition="'$(TargetFramework)' != 'net7.0-windows'">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<InputAssemblies>"$(OutDir)$(TargetFileName)"</InputAssemblies>
|
<InputAssemblies>"$(OutDir)$(TargetFileName)"</InputAssemblies>
|
||||||
|
@ -77,7 +84,7 @@
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<UsingTask TaskName="WinSW.Tasks.Trim" AssemblyFile="$(ArtifactsBinDir)WinSW.Tasks\$(Configuration)\net461\WinSW.Tasks.dll" />
|
<UsingTask TaskName="WinSW.Tasks.Trim" AssemblyFile="$(ArtifactsBinDir)WinSW.Tasks\$(Configuration)\net461\WinSW.Tasks.dll" />
|
||||||
<Target Name="Trim" AfterTargets="Merge" Condition="'$(TargetFramework)' != 'net6.0-windows'">
|
<Target Name="Trim" AfterTargets="Merge" Condition="'$(TargetFramework)' != 'net7.0-windows'">
|
||||||
<Trim Path="$(ArtifactsPublishDir)WinSW-$(TargetFramework).exe" />
|
<Trim Path="$(ArtifactsPublishDir)WinSW-$(TargetFramework).exe" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue