Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display warning when the agent is run in PowerShell Core #4778

Merged
merged 39 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
334799f
Add new knobs
aleksandrlevochkin Apr 30, 2024
e98c806
Split process finding logic into different files
aleksandrlevochkin Apr 30, 2024
9d27b00
Add job context variable for setting flag if agent is running in Powe…
aleksandrlevochkin Apr 30, 2024
42a5972
Add PsModulePath parsing logic
aleksandrlevochkin Apr 30, 2024
9731af5
Comment out some tests temporarily
aleksandrlevochkin Apr 30, 2024
a9fe468
Merge branch 'master' into users/levochkin/fix-psmodulepath
aleksandrlevochkin May 7, 2024
edc5adc
Merge
aleksandrlevochkin May 7, 2024
1657ffa
Add more telemetry
aleksandrlevochkin May 8, 2024
492033a
Add process disposal
aleksandrlevochkin May 8, 2024
e36006b
Extract PsModulePath util
aleksandrlevochkin May 8, 2024
bacdbd3
Add unit tests
aleksandrlevochkin May 8, 2024
42ff977
Merge branch 'users/levochkin/fix-psmodulepath' of https://github.com…
aleksandrlevochkin May 8, 2024
bb9ae4d
Check local env variable before system one (for vso commands)
aleksandrlevochkin May 13, 2024
6ea0fc5
Resolve conflicts
aleksandrlevochkin May 13, 2024
902d866
Extend PsModulePath modification for cases when agent is started in cmd
aleksandrlevochkin May 13, 2024
8753337
Add warning
aleksandrlevochkin May 16, 2024
6fd0d37
Add localization
aleksandrlevochkin May 16, 2024
a2a9dab
Refactor handler
aleksandrlevochkin May 16, 2024
75db55b
Clean up code
aleksandrlevochkin May 16, 2024
5068785
Merge branch 'master' into users/levochkin/fix-psmodulepath
aleksandrlevochkin May 19, 2024
898afbf
Merge branch 'master' into users/levochkin/fix-psmodulepath
aleksandrlevochkin May 22, 2024
a188457
Change how warning message is produced in Agent.Listener
aleksandrlevochkin May 24, 2024
dd7837f
Change knob
aleksandrlevochkin May 24, 2024
30512ff
Modify localization messages
aleksandrlevochkin May 24, 2024
6cd2f8c
Refactor WindowsProcessUtil
aleksandrlevochkin May 24, 2024
97cfbc8
Bring back PsModulePath parsing util
aleksandrlevochkin May 24, 2024
f3af618
Add checks to handler
aleksandrlevochkin May 24, 2024
f8738a1
Fix tests
aleksandrlevochkin May 24, 2024
b8153f5
Remove UseInterop
aleksandrlevochkin May 24, 2024
7f5ee11
Cleanup
aleksandrlevochkin May 27, 2024
9e61cfb
Remove comment
aleksandrlevochkin May 28, 2024
dc2b4f1
Merge branch 'master' of https://github.com/microsoft/azure-pipelines…
aleksandrlevochkin May 28, 2024
5910d1e
Merge branch 'master' into users/levochkin/fix-psmodulepath
aleksandrlevochkin May 28, 2024
f1698e7
Fix test
aleksandrlevochkin May 28, 2024
c857b51
Merge branch 'users/levochkin/fix-psmodulepath' of https://github.com…
aleksandrlevochkin May 28, 2024
2c4df88
Change error description
aleksandrlevochkin May 29, 2024
518760e
Merge branch 'master' into users/levochkin/fix-psmodulepath
kirill-ivlev May 31, 2024
f5c921e
Merge branch 'master' into users/levochkin/fix-psmodulepath
kirill-ivlev Jun 11, 2024
7ece459
Merge branch 'master' into users/levochkin/fix-psmodulepath
kirill-ivlev Jun 11, 2024
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
13 changes: 13 additions & 0 deletions src/Agent.Listener/Agent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using Microsoft.VisualStudio.Services.Agent.Listener.Telemetry;
using System.Collections.Generic;
using Newtonsoft.Json;
using Agent.Sdk.Knob;

namespace Microsoft.VisualStudio.Services.Agent.Listener
{
Expand Down Expand Up @@ -326,6 +327,18 @@ private async Task<int> RunAsync(AgentSettings settings, bool runOnce = false)
try
{
Trace.Info(nameof(RunAsync));

if (PlatformUtil.RunningOnWindows && AgentKnobs.CheckPsModulesLocations.GetValue(HostContext).AsBoolean())
{
string psModulePath = Environment.GetEnvironmentVariable("PSModulePath");
bool containsPwshLocations = PsModulePathUtil.ContainsPowershellCoreLocations(psModulePath);

if (containsPwshLocations)
{
_term.WriteLine(StringUtil.Loc("PSModulePathLocations"));
}
}

_listener = HostContext.GetService<IMessageListener>();
if (!await _listener.CreateSessionAsync(HostContext.AgentShutdownToken))
{
Expand Down
13 changes: 6 additions & 7 deletions src/Agent.Sdk/Knob/AgentKnobs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -678,13 +678,6 @@ public class AgentKnobs
new EnvironmentKnobSource("AGENT_KEY_USE_CNG"),
new BuiltInDefaultKnobSource("false"));

public static readonly Knob UseInteropToFindParentProcess = new Knob(
nameof(UseInteropToFindParentProcess),
"Uses native Windows function to find parent processes of a process.",
new RuntimeKnobSource("AZP_AGENT_USE_INTEROP_TO_FIND_PARENT_PROCESS"),
new EnvironmentKnobSource("AZP_AGENT_USE_INTEROP_TO_FIND_PARENT_PROCESS"),
new BuiltInDefaultKnobSource("false"));

public static readonly Knob RsaKeyGetConfigFromFF = new Knob(
nameof(RsaKeyGetConfigFromFF),
"Get config from FF.",
Expand All @@ -705,5 +698,11 @@ public class AgentKnobs
new EnvironmentKnobSource("ROSETTA2_WARNING"),
new PipelineFeatureSource("Rosetta2Warning"),
new BuiltInDefaultKnobSource("false"));

public static readonly Knob CheckPsModulesLocations = new Knob(
nameof(CheckPsModulesLocations),
"Checks if the PSModulePath environment variable contains locations specific to PowerShell Core.",
new EnvironmentKnobSource("AZP_AGENT_CHECK_PSMODULES_LOCATIONS"),
new BuiltInDefaultKnobSource("false"));
}
}
162 changes: 0 additions & 162 deletions src/Agent.Sdk/Util/ProcessUtil.cs

This file was deleted.

38 changes: 38 additions & 0 deletions src/Agent.Sdk/Util/PsModulePathUtil.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Microsoft.IdentityModel.Tokens;
using System;
using System.IO;
using System.Linq;
using System.Runtime.Versioning;

namespace Agent.Sdk.Util
{
public static class PsModulePathUtil
{
[SupportedOSPlatform("windows")]
public static bool ContainsPowershellCoreLocations(string psModulePath)
{
if (psModulePath.IsNullOrEmpty())
{
return false;
}

string programFilesPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
string programFilesPath86 = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);

string psHomeModuleLocation = Path.Combine(programFilesPath, "PowerShell", "Modules");
string psHomeModuleLocation86 = Path.Combine(programFilesPath86, "PowerShell", "Modules");

string programFilesModuleLocation = Path.Combine(programFilesPath.ToLower(), "powershell", "7", "Modules");
string programFilesModuleLocation86 = Path.Combine(programFilesPath86.ToLower(), "powershell", "7", "Modules");

string[] wellKnownLocations = new[]
{
psHomeModuleLocation, psHomeModuleLocation86, programFilesModuleLocation, programFilesModuleLocation86
};

bool containsPwshLocations = wellKnownLocations.Any(location => psModulePath.Contains(location, StringComparison.OrdinalIgnoreCase));

return containsPwshLocations;
}
}
}
79 changes: 79 additions & 0 deletions src/Agent.Sdk/Util/WindowsProcessUtil.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Management;

namespace Microsoft.VisualStudio.Services.Agent.Util
{
internal record ProcessInfo(int ProcessId, string ProcessName);

public static class WindowsProcessUtil
{
internal static ProcessInfo GetParentProcessInformation(int processId)
{
using var query = new ManagementObjectSearcher($"SELECT ParentProcessId FROM Win32_Process WHERE ProcessId={processId}");

using ManagementObjectCollection queryResult = query.Get();

using ManagementObject foundProcess = queryResult.OfType<ManagementObject>().FirstOrDefault();
kirill-ivlev marked this conversation as resolved.
Show resolved Hide resolved

if (foundProcess == null)
{
return null;
}

int parentProcessId = (int)(uint)foundProcess["ParentProcessId"];

try
{
using var parentProcess = Process.GetProcessById(parentProcessId);
return new(parentProcess.Id, parentProcess.ProcessName);
}
catch (InvalidOperationException)
{
return null;
}
catch (ArgumentException)
{
return null;
}
}

internal static List<ProcessInfo> GetProcessList()
{
using var currentProcess = Process.GetCurrentProcess();
var currentProcessInfo = new ProcessInfo(currentProcess.Id, currentProcess.ProcessName);

var processes = new List<ProcessInfo>() { new(currentProcessInfo.ProcessId, currentProcessInfo.ProcessName) };

const int maxSearchDepthForProcess = 10;

while (processes.Count < maxSearchDepthForProcess)
{
ProcessInfo lastProcessInfo = processes.Last();
ProcessInfo parentProcessInfo = GetParentProcessInformation(lastProcessInfo.ProcessId);

if (parentProcessInfo == null)
{
return processes;
}

processes.Add(parentProcessInfo);
}

return processes;
}

public static bool IsAgentRunningInPowerShellCore()
{
List<ProcessInfo> processList = GetProcessList();

bool isProcessRunningInPowerShellCore = processList.Exists(process => process.ProcessName == "pwsh");

return isProcessRunningInPowerShellCore;
}
}
}
Loading
Loading