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
3 changes: 3 additions & 0 deletions DATA_AND_PRIVACY.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ Thank you for using PowerToys!
| Microsoft.PowerToys.AwakeIndefinitelyKeepAwakeEvent | Triggered when the system is set to stay awake indefinitely. |
| Microsoft.PowerToys.AwakeNoKeepAwakeEvent | Occurs when Awake is turned off, allowing the computer to enter sleep mode. |
| Microsoft.PowerToys.AwakeTimedKeepAwakeEvent | Triggered when the system is kept awake for a specified time duration. |
| Microsoft.PowerToys.Awake_CLICommand | Triggered when an Awake CLI command is executed, logging the command name and success status. |

### Color Picker

Expand Down Expand Up @@ -204,6 +205,7 @@ Thank you for using PowerToys!
| Microsoft.PowerToys.FileLocksmith_Invoked | Occurs when File Locksmith is invoked. |
| Microsoft.PowerToys.FileLocksmith_InvokedRet | Triggered when File Locksmith invocation returns a result. |
| Microsoft.PowerToys.FileLocksmith_QueryContextMenuError | Occurs when there is an error querying the context menu for File Locksmith. |
| Microsoft.PowerToys.FileLocksmith_CLICommand | Triggered when a File Locksmith CLI command is executed, logging the operation mode (query, kill, query-wait, query-json, or help) and success status. |

### FileExplorerAddOns

Expand Down Expand Up @@ -258,6 +260,7 @@ Thank you for using PowerToys!
| Microsoft.PowerToys.ImageResizer_Invoked | Occurs when Image Resizer is invoked by the user. |
| Microsoft.PowerToys.ImageResizer_InvokedRet | Fires when the Image Resizer operation is completed and returns a result. |
| Microsoft.PowerToys.ImageResizer_QueryContextMenuError | Triggered when there is an error querying the context menu for Image Resizer. |
| Microsoft.PowerToys.ImageResizer_CLICommand | Triggered when an Image Resizer CLI command is executed, logging the command name and success status. |

### Keyboard Manager

Expand Down
17 changes: 9 additions & 8 deletions src/modules/FileLocksmith/FileLocksmithCLI/CLILogic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ CommandResult run_command(int argc, wchar_t* argv[], IProcessFinder& finder, IPr
if (argc < 2)
{
Logger::warn("No arguments provided");
return { 1, get_usage(strings) };
return { 1, get_usage(strings), L"help" };
}

bool json_output = false;
Expand Down Expand Up @@ -156,18 +156,18 @@ CommandResult run_command(int argc, wchar_t* argv[], IProcessFinder& finder, IPr
catch (...)
{
Logger::error("Invalid timeout value");
return { 1, strings.GetString(IDS_ERROR_INVALID_TIMEOUT) };
return { 1, strings.GetString(IDS_ERROR_INVALID_TIMEOUT), L"query-wait" };
}
}
else
{
Logger::error("Timeout argument missing");
return { 1, strings.GetString(IDS_ERROR_TIMEOUT_ARG) };
return { 1, strings.GetString(IDS_ERROR_TIMEOUT_ARG), L"query-wait" };
}
}
else if (arg == L"--help")
{
return { 0, get_usage(strings) };
return { 0, get_usage(strings), L"help" };
}
else
{
Expand All @@ -178,7 +178,7 @@ CommandResult run_command(int argc, wchar_t* argv[], IProcessFinder& finder, IPr
if (paths.empty())
{
Logger::error("No paths specified");
return { 1, strings.GetString(IDS_ERROR_NO_PATHS) };
return { 1, strings.GetString(IDS_ERROR_NO_PATHS), L"query" };
}

Logger::info("Processing {} paths", paths.size());
Expand Down Expand Up @@ -213,13 +213,13 @@ CommandResult run_command(int argc, wchar_t* argv[], IProcessFinder& finder, IPr
{
Logger::warn("Timeout waiting for files to be unlocked");
ss << strings.GetString(IDS_TIMEOUT);
return { 1, ss.str() };
return { 1, ss.str(), L"query-wait" };
}
}

Sleep(200);
}
return { 0, ss.str() };
return { 0, ss.str(), L"query-wait" };
}

auto results = finder.find(paths);
Expand All @@ -244,5 +244,6 @@ CommandResult run_command(int argc, wchar_t* argv[], IProcessFinder& finder, IPr
output_ss << get_text(results, strings);
}

return { 0, output_ss.str() };
std::wstring cmd_name = kill ? L"kill" : (json_output ? L"query-json" : L"query");
return { 0, output_ss.str(), cmd_name };
}
1 change: 1 addition & 0 deletions src/modules/FileLocksmith/FileLocksmithCLI/CLILogic.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ struct CommandResult
{
int exit_code;
std::wstring output;
std::wstring command_name;
};

struct IProcessFinder
Expand Down
5 changes: 5 additions & 0 deletions src/modules/FileLocksmith/FileLocksmithCLI/main.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "pch.h"
#include "CLILogic.h"
#include "FileLocksmithLib/FileLocksmith.h"
#include "FileLocksmithLib/Trace.h"
#include <iostream>
#include "resource.h"
#include <common/logger/logger.h>
Expand Down Expand Up @@ -47,6 +48,7 @@ struct RealStringProvider : IStringProvider
int wmain(int argc, wchar_t* argv[])
{
winrt::init_apartment();
Trace::RegisterProvider();
LoggerHelpers::init_logger(L"FileLocksmithCLI", L"", LogSettings::fileLocksmithLoggerName);
Logger::info("FileLocksmithCLI started");

Expand All @@ -65,7 +67,10 @@ int wmain(int argc, wchar_t* argv[])
Logger::info("Command succeeded");
}

Trace::CLICommand(result.command_name.c_str(), result.exit_code == 0);

std::wcout << result.output;
Trace::UnregisterProvider();
return result.exit_code;
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ namespace FileLocksmithCLIUnitTests
auto result = run_command(1, argv, finder, terminator, strings);

Assert::AreEqual(1, result.exit_code);
Assert::AreEqual(std::wstring(L"help"), result.command_name);
}

TEST_METHOD(TestHelp)
Expand All @@ -64,6 +65,7 @@ namespace FileLocksmithCLIUnitTests
auto result = run_command(2, argv, finder, terminator, strings);

Assert::AreEqual(0, result.exit_code);
Assert::AreEqual(std::wstring(L"help"), result.command_name);
}

TEST_METHOD(TestFindProcesses)
Expand All @@ -77,6 +79,7 @@ namespace FileLocksmithCLIUnitTests
auto result = run_command(2, argv, finder, terminator, strings);

Assert::AreEqual(0, result.exit_code);
Assert::AreEqual(std::wstring(L"query"), result.command_name);
Assert::IsTrue(result.output.find(L"123") != std::wstring::npos);
Assert::IsTrue(result.output.find(L"process") != std::wstring::npos);
}
Expand All @@ -94,6 +97,7 @@ namespace FileLocksmithCLIUnitTests
Microsoft::VisualStudio::CppUnitTestFramework::Logger::WriteMessage(result.output.c_str());

Assert::AreEqual(0, result.exit_code);
Assert::AreEqual(std::wstring(L"query-json"), result.command_name);
Assert::IsTrue(result.output.find(L"\"pid\"") != std::wstring::npos);
Assert::IsTrue(result.output.find(L"123") != std::wstring::npos);
}
Expand All @@ -109,6 +113,7 @@ namespace FileLocksmithCLIUnitTests
auto result = run_command(3, argv, finder, terminator, strings);

Assert::AreEqual(0, result.exit_code);
Assert::AreEqual(std::wstring(L"kill"), result.command_name);
Assert::AreEqual((size_t)1, terminator.terminatedPids.size());
Assert::AreEqual((DWORD)123, terminator.terminatedPids[0]);
}
Expand All @@ -125,6 +130,7 @@ namespace FileLocksmithCLIUnitTests
auto result = run_command(5, argv, finder, terminator, strings);

Assert::AreEqual(1, result.exit_code);
Assert::AreEqual(std::wstring(L"query-wait"), result.command_name);
}
};
}
11 changes: 11 additions & 0 deletions src/modules/FileLocksmith/FileLocksmithLib/Trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,14 @@ void Trace::QueryContextMenuError(_In_ HRESULT hr) noexcept
TraceLoggingHResult(hr),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
}

void Trace::CLICommand(_In_ PCWSTR commandName, _In_ bool successful) noexcept
{
TraceLoggingWriteWrapper(
g_hProvider,
"FileLocksmith_CLICommand",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
TraceLoggingWideString(commandName, "CommandName"),
TraceLoggingBoolean(successful, "Successful"));
}
1 change: 1 addition & 0 deletions src/modules/FileLocksmith/FileLocksmithLib/Trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ class Trace : public telemetry::TraceBase
static void Invoked() noexcept;
static void InvokedRet(_In_ HRESULT hr) noexcept;
static void QueryContextMenuError(_In_ HRESULT hr) noexcept;
static void CLICommand(_In_ PCWSTR commandName, _In_ bool successful) noexcept;
};
24 changes: 23 additions & 1 deletion src/modules/awake/Awake/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using Awake.Core.Models;
using Awake.Core.Native;
using Awake.Properties;
using Awake.Telemetry;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Telemetry;
Expand Down Expand Up @@ -68,6 +69,7 @@ private static async Task<int> Main(string[] args)
if (parseResult.Errors.Count > 0)
{
// Shows errors and returns non-zero.
LogCLITelemetry(successful: false);
return rootCommand.Invoke(args);
}

Expand Down Expand Up @@ -96,13 +98,15 @@ private static async Task<int> Main(string[] args)
{
// Awake is already running - there is no need for us to process
// anything further
LogCLITelemetry(successful: false);
Exit(Core.Constants.AppName + " is already running! Exiting the application.", 1);
return 1;
}
else
{
if (PowerToys.GPOWrapper.GPOWrapper.GetConfiguredAwakeEnabledValue() == PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
{
LogCLITelemetry(successful: false);
Exit("PowerToys.Awake tried to start with a group policy setting that disables the tool. Please contact your system administrator.", 1);
return 1;
}
Comment thread
MuyuanMS marked this conversation as resolved.
Expand All @@ -125,7 +129,9 @@ private static async Task<int> Main(string[] args)
Bridge.GetPwrCapabilities(out _powerCapabilities);
Logger.LogInfo(JsonSerializer.Serialize(_powerCapabilities, _serializerOptions));

return await rootCommand.InvokeAsync(args);
var result = await rootCommand.InvokeAsync(args);
LogCLITelemetry(successful: result == 0);
return result;
}
}
}
Expand Down Expand Up @@ -216,6 +222,22 @@ private static RootCommand BuildRootCommand()
return rootCommand;
}

private static void LogCLITelemetry(bool successful)
{
try
{
PowerToysTelemetry.Log.WriteEvent(new AwakeCLICommandEvent
{
CommandName = "awake",
Successful = successful,
});
}
catch (Exception ex)
{
Logger.LogError($"Failed to log CLI telemetry: {ex.Message}");
}
}

private static void AwakeUnhandledExceptionCatcher(object sender, UnhandledExceptionEventArgs e)
{
if (e.ExceptionObject is Exception exception)
Expand Down
37 changes: 37 additions & 0 deletions src/modules/awake/Awake/Telemetry/AwakeCLICommandEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;

namespace Awake.Telemetry
{
/// <summary>
/// Telemetry event for Awake CLI command execution.
/// </summary>
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class AwakeCLICommandEvent : EventBase, IEvent
{
public AwakeCLICommandEvent()
{
EventName = "Awake_CLICommand";
CommandName = string.Empty;
}

/// <summary>
/// Gets or sets the name of the CLI command that was executed.
/// </summary>
public string CommandName { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the command executed successfully.
/// </summary>
public bool Successful { get; set; }

public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}
}
23 changes: 22 additions & 1 deletion src/modules/imageresizer/ImageResizerCLI/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
using System.Text;

using ImageResizer.Cli;
using ImageResizer.Cli.Telemetry;
using ManagedCommon;
using Microsoft.PowerToys.Telemetry;

namespace ImageResizerCLI;

Expand Down Expand Up @@ -37,14 +39,33 @@ private static int Main(string[] args)
try
{
var executor = new ImageResizerCliExecutor();
return executor.Run(args);
int result = executor.Run(args);
LogCLITelemetry(executor.CommandName, result == 0);
return result;
}
catch (Exception ex)
{
CliLogger.Error($"Unhandled exception: {ex.Message}");
CliLogger.Error($"Stack trace: {ex.StackTrace}");
Console.Error.WriteLine($"Fatal error: {ex.Message}");
LogCLITelemetry("resize", successful: false);
return 1;
}
}

private static void LogCLITelemetry(string commandName, bool successful)
{
try
{
PowerToysTelemetry.Log.WriteEvent(new ImageResizerCLICommandEvent
{
CommandName = commandName,
Successful = successful,
});
}
catch (Exception ex)
{
CliLogger.Error($"Failed to log CLI telemetry: {ex.Message}");
}
}
}
9 changes: 9 additions & 0 deletions src/modules/imageresizer/ui/Cli/ImageResizerCliExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ namespace ImageResizer.Cli
/// </summary>
public class ImageResizerCliExecutor
{
/// <summary>
/// Gets the name of the last CLI operation that was executed.
/// </summary>
public string CommandName { get; private set; } = "resize";

/// <summary>
/// Runs the CLI executor with the provided command-line arguments.
/// </summary>
Expand All @@ -37,25 +42,29 @@ public int Run(string[] args)
}

CliOptions.PrintUsage();
CommandName = "error";
return 1;
}

if (cliOptions.ShowHelp)
{
CliOptions.PrintUsage();
CommandName = "help";
return 0;
}

if (cliOptions.ShowConfig)
{
CliOptions.PrintConfig(Settings.Default);
CommandName = "show-config";
return 0;
}

if (cliOptions.Files.Count == 0 && string.IsNullOrEmpty(cliOptions.PipeName))
{
Console.WriteLine(Resources.CLI_NoInputFiles);
CliOptions.PrintUsage();
CommandName = "error";
return 1;
}

Expand Down
Loading
Loading