Skip to content

Commit 2ec6943

Browse files
pontemontiJohan Broberg
andauthored
Run PowerShell script in MicrosoftGraphTokenProvider in interactive mode (#142)
* Update ExecutePowerShellAsync in MicrosoftGraphTokenProvider to always run in interactive mode. * Update tests --------- Co-authored-by: Johan Broberg <johanb@microsoft.com>
1 parent da2365e commit 2ec6943

File tree

2 files changed

+24
-41
lines changed

2 files changed

+24
-41
lines changed

src/Microsoft.Agents.A365.DevTools.Cli/Services/Internal/MicrosoftGraphTokenProvider.cs

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public MicrosoftGraphTokenProvider(
108108
useDeviceCode);
109109

110110
var script = BuildPowerShellScript(tenantId, validatedScopes, useDeviceCode, clientAppId);
111-
var result = await ExecuteWithFallbackAsync(script, useDeviceCode, ct);
111+
var result = await ExecuteWithFallbackAsync(script, ct);
112112
var token = ProcessResult(result);
113113

114114
if (string.IsNullOrWhiteSpace(token))
@@ -216,17 +216,16 @@ private static string BuildScopesArray(string[] scopes)
216216

217217
private async Task<CommandResult> ExecuteWithFallbackAsync(
218218
string script,
219-
bool useDeviceCode,
220219
CancellationToken ct)
221220
{
222221
// Try PowerShell Core first (cross-platform)
223-
var result = await ExecutePowerShellAsync("pwsh", script, useDeviceCode, ct);
222+
var result = await ExecutePowerShellAsync("pwsh", script, ct);
224223

225224
// Fallback to Windows PowerShell if pwsh is not available
226225
if (!result.Success && IsPowerShellNotFoundError(result))
227226
{
228227
_logger.LogDebug("PowerShell Core not found, falling back to Windows PowerShell");
229-
result = await ExecutePowerShellAsync("powershell", script, useDeviceCode, ct);
228+
result = await ExecutePowerShellAsync("powershell", script, ct);
230229
}
231230

232231
return result;
@@ -235,33 +234,17 @@ private async Task<CommandResult> ExecuteWithFallbackAsync(
235234
private async Task<CommandResult> ExecutePowerShellAsync(
236235
string shell,
237236
string script,
238-
bool useDeviceCode,
239237
CancellationToken ct)
240238
{
241239
var arguments = BuildPowerShellArguments(shell, script);
242240

243-
if (useDeviceCode)
244-
{
245-
// Use streaming for device code flow so user sees the instructions in real-time
246-
return await _executor.ExecuteWithStreamingAsync(
247-
command: shell,
248-
arguments: arguments,
249-
workingDirectory: null,
250-
outputPrefix: "",
251-
interactive: true, // Allow user to see device code instructions
252-
cancellationToken: ct);
253-
}
254-
else
255-
{
256-
// Use standard execution for browser flow (captures output silently)
257-
return await _executor.ExecuteAsync(
258-
command: shell,
259-
arguments: arguments,
260-
workingDirectory: null,
261-
captureOutput: true,
262-
suppressErrorLogging: true, // We handle logging ourselves
263-
cancellationToken: ct);
264-
}
241+
return await _executor.ExecuteWithStreamingAsync(
242+
command: shell,
243+
arguments: arguments,
244+
workingDirectory: null,
245+
outputPrefix: "",
246+
interactive: true,
247+
cancellationToken: ct);
265248
}
266249

267250
private static string BuildPowerShellArguments(string shell, string script)

src/Tests/Microsoft.Agents.A365.DevTools.Cli.Tests/Services/MicrosoftGraphTokenProviderTests.cs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ public async Task GetMgGraphAccessTokenAsync_WithValidClientAppId_IncludesClient
2929
var clientAppId = "87654321-4321-4321-4321-cba987654321";
3030
var expectedToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.signature";
3131

32-
_executor.ExecuteAsync(
32+
_executor.ExecuteWithStreamingAsync(
3333
Arg.Any<string>(),
3434
Arg.Is<string>(args => args.Contains($"-ClientId '{clientAppId}'")),
3535
Arg.Any<string?>(),
36-
Arg.Any<bool>(),
36+
Arg.Any<string>(),
3737
Arg.Any<bool>(),
3838
Arg.Any<CancellationToken>())
3939
.Returns(new CommandResult { ExitCode = 0, StandardOutput = expectedToken, StandardError = string.Empty });
@@ -45,11 +45,11 @@ public async Task GetMgGraphAccessTokenAsync_WithValidClientAppId_IncludesClient
4545

4646
// Assert
4747
token.Should().Be(expectedToken);
48-
await _executor.Received(1).ExecuteAsync(
48+
await _executor.Received(1).ExecuteWithStreamingAsync(
4949
Arg.Is<string>(cmd => cmd == "pwsh" || cmd == "powershell"),
5050
Arg.Is<string>(args => args.Contains($"-ClientId '{clientAppId}'")),
5151
Arg.Any<string?>(),
52-
Arg.Any<bool>(),
52+
Arg.Any<string>(),
5353
Arg.Any<bool>(),
5454
Arg.Any<CancellationToken>());
5555
}
@@ -62,11 +62,11 @@ public async Task GetMgGraphAccessTokenAsync_WithoutClientAppId_OmitsClientIdPar
6262
var scopes = new[] { "User.Read" };
6363
var expectedToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.signature";
6464

65-
_executor.ExecuteAsync(
65+
_executor.ExecuteWithStreamingAsync(
6666
Arg.Any<string>(),
6767
Arg.Is<string>(args => !args.Contains("-ClientId")),
6868
Arg.Any<string?>(),
69-
Arg.Any<bool>(),
69+
Arg.Any<string>(),
7070
Arg.Any<bool>(),
7171
Arg.Any<CancellationToken>())
7272
.Returns(new CommandResult { ExitCode = 0, StandardOutput = expectedToken, StandardError = string.Empty });
@@ -78,11 +78,11 @@ public async Task GetMgGraphAccessTokenAsync_WithoutClientAppId_OmitsClientIdPar
7878

7979
// Assert
8080
token.Should().Be(expectedToken);
81-
await _executor.Received(1).ExecuteAsync(
81+
await _executor.Received(1).ExecuteWithStreamingAsync(
8282
Arg.Any<string>(),
8383
Arg.Is<string>(args => !args.Contains("-ClientId")),
8484
Arg.Any<string?>(),
85-
Arg.Any<bool>(),
85+
Arg.Any<string>(),
8686
Arg.Any<bool>(),
8787
Arg.Any<CancellationToken>());
8888
}
@@ -152,11 +152,11 @@ public async Task GetMgGraphAccessTokenAsync_WhenExecutionFails_ReturnsNull()
152152
var tenantId = "12345678-1234-1234-1234-123456789abc";
153153
var scopes = new[] { "User.Read" };
154154

155-
_executor.ExecuteAsync(
155+
_executor.ExecuteWithStreamingAsync(
156156
Arg.Any<string>(),
157157
Arg.Any<string>(),
158158
Arg.Any<string?>(),
159-
Arg.Any<bool>(),
159+
Arg.Any<string>(),
160160
Arg.Any<bool>(),
161161
Arg.Any<CancellationToken>())
162162
.Returns(new CommandResult { ExitCode = 1, StandardOutput = string.Empty, StandardError = "PowerShell error" });
@@ -178,11 +178,11 @@ public async Task GetMgGraphAccessTokenAsync_WithValidToken_ReturnsToken()
178178
var scopes = new[] { "User.Read" };
179179
var expectedToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.signature";
180180

181-
_executor.ExecuteAsync(
181+
_executor.ExecuteWithStreamingAsync(
182182
Arg.Any<string>(),
183183
Arg.Any<string>(),
184184
Arg.Any<string?>(),
185-
Arg.Any<bool>(),
185+
Arg.Any<string>(),
186186
Arg.Any<bool>(),
187187
Arg.Any<CancellationToken>())
188188
.Returns(new CommandResult { ExitCode = 0, StandardOutput = expectedToken, StandardError = string.Empty });
@@ -223,11 +223,11 @@ public async Task GetMgGraphAccessTokenAsync_EscapesSingleQuotesInClientAppId()
223223
var clientAppId = "87654321-4321-4321-4321-cba987654321";
224224
var expectedToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.signature";
225225

226-
_executor.ExecuteAsync(
226+
_executor.ExecuteWithStreamingAsync(
227227
Arg.Any<string>(),
228228
Arg.Is<string>(args => !args.Contains("''")), // Should not have escaped quotes for valid GUID
229229
Arg.Any<string?>(),
230-
Arg.Any<bool>(),
230+
Arg.Any<string>(),
231231
Arg.Any<bool>(),
232232
Arg.Any<CancellationToken>())
233233
.Returns(new CommandResult { ExitCode = 0, StandardOutput = expectedToken, StandardError = string.Empty });

0 commit comments

Comments
 (0)