Skip to content

Commit e15adca

Browse files
committed
Version 1.0.3.1
1 parent 609fd76 commit e15adca

File tree

66 files changed

+463
-249
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+463
-249
lines changed

Docs/Job.md

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,25 @@ Your PowerCommands application may of course have so other name and your command
1414
"powercommands.exe job argument1"
1515
```
1616

17+
## What if the command you want to run just once is not designed to quit?
18+
If the command inherits from the CommandBase class, which most if not all Commands are, you can use the option `--pc_force_quit` to quit the application after the command is finished. If the command is running as async, this could cause unexpected behavior, be aware of that.
19+
1720
## Run PowerCommand with a service account and use secrets
18-
If you want to run your PowerCommands application as a Windows scheduled task started by a service accounts that is not allowed to login on the machine, you need to do a couple of steps.
21+
If you want to run your PowerCommands application as a Windows scheduled task started by a service accounts that is not allowed to login on the machine, you need to do a couple of steps to make sure that the service account user can use the decryption functionality.
22+
The easy way is to delete the setup.yaml file in the application folder and start your Power Command application again, this will guide you through the setup.
23+
24+
- First answer `y` to the question if you want to setup encryption.
25+
- Answer `y` to the question that you intend to run your application using a service account.
26+
- Last you need to update the `PowerCommandsConfiguration.yaml` file with the encryption element.
1927

20-
- You need to copy the PainKiller directory from your %User%\AppData\Roaming to the corresponding one for the service account.
21-
- Copy the environment variable _encryptionManager and create the same as a system environment variable. EncryptionService will look for the system environment variable if the user environment variable is not there.
22-
- For your stored secrets you will need to to do the same thing and change target: User to target: Machine in the **PowerCommandsConfiguration.yaml** file.
28+
It could look something like this:
29+
```
30+
encryption:
31+
sharedSecretEnvironmentKey: '_encryptionManager'
32+
sharedSecretSalt: WJtOL/ZgbHwVhbL76JGFyA==
33+
iterationCount: 10000
34+
keySize: 256
35+
```
2336

2437
Read more about:
2538

PC_Nov_2023_src.zip

12.1 MB
Binary file not shown.

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,15 @@ You could see PowerCommands as your CLI application starter kit. It is a structu
33

44
[Follow progress on twitter](https://twitter.com/PowerCommands) <img src="https://github.com/PowerCommands/PowerCommands2022/blob/main/Docs/images/Twitter.png?raw=true" alt="drawing" width="20"/>
55

6-
**Latest release 2023-11-18**
6+
## Version 1.0.3.1
7+
**Released 2023-11-30**
8+
- Adjusted the Power Command to use be run with a service account and use encryption, update the setup to reflect this.
9+
- Added general option --pc_force_quit in CommandBase to be used with any command to force application to quit.
10+
- Improved encryption
11+
- Bug fix DialogService.ListDialog now handles 0 input more gracefully
12+
- Bug fix CommandBase now return RunResultStatus.Quit when using Quit()
13+
14+
**Release 2023-11-18**
715
- Updated to .NET 8
816
- Using C# 12
917
- Updated YamlDotNet to current latest stable version

Templates/PowerCommands.zip

8.2 KB
Binary file not shown.

Templates/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ I recommend you to use the option ```Place solution in the same directory``` som
1616
![Alt text](../Docs/images/VS_solution_option.png?raw=true "Command Base")
1717

1818
# What is new?
19+
## Version 1.0.3.1
20+
**Released 2023-11-30**
21+
- Adjusted the Power Command to use be run with a service account and use encryption, update the setup to reflect this.
22+
- Added general option --pc_force_quit in CommandBase to be used with any command to force application to quit.
23+
- Improved encryption
24+
- Bug fix DialogService.ListDialog now handles 0 input more gracefully
25+
- Bug fix CommandBase now return RunResultStatus.Quit when using Quit()
1926
## Version 1.0.3.0
2027
**Released 2023-11-18**
2128
- Updated to .NET 8

Templates/src/Core/PainKiller.PowerCommands.Configuration/CONTRACTS/IConfigurationService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ public interface IConfigurationService
88
string SaveChanges<T>(T configuration, string inputFileName = "") where T : new();
99
void Create<T>(T configuration, string fullFileName) where T : new();
1010
YamlContainer<T> GetAppDataConfiguration<T>(string inputFileName = "") where T : new();
11+
YamlContainer<T> GetByNodeName<T>(string filePath, string nodeName) where T : new();
1112
}

Templates/src/Core/PainKiller.PowerCommands.Configuration/ConfigurationService.cs

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using $safeprojectname$.Contracts;
1+
using System.Text;
2+
using $safeprojectname$.Contracts;
23
using $safeprojectname$.DomainObjects;
34
using $safeprojectname$.Extensions;
45
using YamlDotNet.Serialization;
@@ -32,6 +33,46 @@ private ConfigurationService(){}
3233
return new YamlContainer<T>();
3334
}
3435
}
36+
public YamlContainer<T> GetByNodeName<T>(string filePath, string nodeName) where T : new()
37+
{
38+
var stringBuilder = new StringBuilder();
39+
stringBuilder.AppendLine("version: 1.0\r\nconfiguration:");
40+
var nodeFound = false;
41+
var nodeIndentation = 0;
42+
43+
using (var reader = new StreamReader(filePath))
44+
{
45+
while (reader.ReadLine() is { } line)
46+
{
47+
if (line.Trim().StartsWith(nodeName + ":"))
48+
{
49+
nodeFound = true;
50+
nodeIndentation = line.TakeWhile(Char.IsWhiteSpace).Count();
51+
stringBuilder.AppendLine(line);
52+
continue;
53+
}
54+
if (!nodeFound) continue;
55+
var currentIndentation = line.TakeWhile(Char.IsWhiteSpace).Count();
56+
if (string.IsNullOrWhiteSpace(line) || currentIndentation <= nodeIndentation) break;
57+
stringBuilder.AppendLine(line);
58+
}
59+
}
60+
61+
var yamlContent = stringBuilder.ToString();
62+
var deserializer = new DeserializerBuilder()
63+
.WithNamingConvention(CamelCaseNamingConvention.Instance)
64+
.Build();
65+
try
66+
{
67+
return deserializer.Deserialize<YamlContainer<T>>(yamlContent);
68+
}
69+
catch (Exception)
70+
{
71+
Console.WriteLine($"Could not deserialize the configuration file, default configuration will be loaded instead\nA template configuration file named default_{typeof(T).Name}.yaml will be created in application root.");
72+
return new YamlContainer<T>();
73+
}
74+
75+
}
3576
public string SaveChanges<T>(T configuration, string inputFileName = "") where T : new()
3677
{
3778
if (configuration is null) return "";
@@ -45,7 +86,6 @@ private ConfigurationService(){}
4586
File.WriteAllText(fileName, yamlData);
4687
return fileName;
4788
}
48-
4989
public void Create<T>(T configuration, string fullFileName) where T : new()
5090
{
5191
if (configuration is null) return;
@@ -67,9 +107,8 @@ private ConfigurationService(){}
67107
public YamlContainer<T> GetAppDataConfiguration<T>(string inputFileName = "") where T : new()
68108
{
69109
var directory = $"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\\{nameof(PowerCommands)}";
70-
if (!Directory.Exists(directory)) Directory.CreateDirectory(directory);
71110
var fileName = Path.Combine(directory, inputFileName);
72-
if (!File.Exists(fileName)) throw new FileNotFoundException($"Could not find file {fileName}");
111+
if (!File.Exists(fileName)) return new YamlContainer<T>();
73112
var yamlContent = File.ReadAllText(fileName);
74113
var deserializer = new DeserializerBuilder()
75114
.WithNamingConvention(CamelCaseNamingConvention.Instance)

Templates/src/Core/PainKiller.PowerCommands.Configuration/DOMAINOBJECTS/ConfigurationGlobals.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ public static class ConfigurationGlobals
77
public const string SecurityFileName = "security.yaml";
88
public const string WhatsNewFileName = "whats_new.md";
99
public const char ArraySplitter = '|';
10+
public const string SetupConfigurationFile = "setup.yaml";
11+
public const string EncryptionEnviromentVariableName = "_encryptionManager";
1012

1113
public static readonly string ApplicationDataFolder = $"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\\{nameof(PowerCommands)}";
1214
}

Templates/src/Core/PainKiller.PowerCommands.Configuration/DOMAINOBJECTS/EncryptionConfiguration.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ public class EncryptionConfiguration
44
{
55
public string SharedSecretEnvironmentKey { get; set; } = "";
66
public string SharedSecretSalt { get; set; } = "";
7+
public int IterationCount { get; set; } = 10000;
8+
public int KeySize { get; set; } = 256;
79
}

Templates/src/Core/PainKiller.PowerCommands.Configuration/EXTENSIONS/ConfigurationExtension.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using $safeprojectname$.DomainObjects;
2+
using YamlDotNet.Serialization.NamingConventions;
3+
using YamlDotNet.Serialization;
24

35
namespace $safeprojectname$.Extensions;
46

@@ -15,4 +17,11 @@ public static string GetPath(this ArtifactPathsConfiguration configuration, stri
1517
return Path.Combine(ReplaceTags(paths[0], configuration.Name), ReplaceTags(paths[1], configuration.Name), ReplaceTags(paths[2], configuration.Name));
1618
}
1719
private static string ReplaceTags(string raw, string name) => raw.Replace("{appdata}", AppContext.BaseDirectory).Replace("{name}", name);
20+
public static string GetYaml<T>(this T configuration) where T : new()
21+
{
22+
var serializer = new SerializerBuilder()
23+
.WithNamingConvention(CamelCaseNamingConvention.Instance)
24+
.Build();
25+
return serializer.Serialize(configuration);
26+
}
1827
}

0 commit comments

Comments
 (0)