diff --git a/package.json b/package.json index 593678485a..9d3dba87a6 100644 --- a/package.json +++ b/package.json @@ -519,7 +519,7 @@ } }, { - "label": "Run Pester Tests (Binary Module)", + "label": "PowerShell: Run Pester Tests (Binary Module)", "description": "Debug a .NET binary or hybrid module by running Pester tests. Breakpoints you set in your .NET (C#/F#/VB/etc.) code will be hit upon command execution. You may want to add a compile or watch action as a pre-launch task to this configuration.", "body": { "name": "PowerShell: Binary Module Pester Tests", @@ -529,6 +529,16 @@ "createTemporaryIntegratedConsole": true, "attachDotnetDebugger": true } + }, + { + "label": "PowerShell: Windows PowerShell", + "description": "(Windows Only) Launch a temporary Windows PowerShell console for debugging. This is useful for debugging legacy scripts that require Windows PowerShell.", + "body": { + "name": "PowerShell: Windows PowerShell", + "type": "PowerShell", + "request": "launch", + "sessionName": "Windows PowerShell (x64)" + } } ], "configurationAttributes": { @@ -556,6 +566,14 @@ "description": "Determines whether a temporary PowerShell Extension Terminal is created for each debugging session, useful for debugging PowerShell classes and binary modules. Overrides the user setting 'powershell.debugging.createTemporaryIntegratedConsole'.", "default": false }, + "sessionName": { + "type": [ + "string", + "null" + ], + "description": "If specified, uses the PowerShell session name to launch the debug configuration. Will always launch in a temporary console if specified.", + "default": null + }, "attachDotnetDebugger": { "type": "boolean", "description": "If specified, a C# debug session will be started and attached to the new temporary extension terminal. This does nothing unless 'powershell.debugging.createTemporaryIntegratedConsole' is also specified.", diff --git a/src/features/DebugSession.ts b/src/features/DebugSession.ts index f45e674fb9..3128db3b46 100644 --- a/src/features/DebugSession.ts +++ b/src/features/DebugSession.ts @@ -56,6 +56,7 @@ export enum DebugConfig { ModuleInteractiveSession, BinaryModule, BinaryModulePester, + WindowsPowerShell, } /** Make the implicit behavior of undefined and null in the debug api more explicit */ @@ -126,6 +127,12 @@ export const DebugConfigurations: Record = { createTemporaryIntegratedConsole: true, attachDotnetDebugger: true, }, + [DebugConfig.WindowsPowerShell]: { + name: "PowerShell: Windows PowerShell", + type: "PowerShell", + request: "launch", + sessionName: "Windows PowerShell (x64)", + }, }; export class DebugSessionFeature @@ -271,13 +278,24 @@ export class DebugSessionFeature "Debug a .NET binary or hybrid module loaded into a PowerShell session. Breakpoints you set in your .NET (C#/F#/VB/etc.) code will be hit upon command execution. You may want to add a compile or watch action as a pre-launch task to this configuration.", }, { - id: DebugConfig.RunPester, + id: DebugConfig.BinaryModulePester, label: "Run Pester Tests (Binary Module)", description: "Debug a .NET binary or hybrid module by running Pester tests. Breakpoints you set in your .NET (C#/F#/VB/etc.) code will be hit upon command execution. You may want to add a compile or watch action as a pre-launch task to this configuration.", }, ]; + // Only show the Windows PowerShell option if the platform is Windows + const platformDetails = getPlatformDetails(); + if (platformDetails.operatingSystem === OperatingSystem.Windows) { + debugConfigPickItems.push({ + id: DebugConfig.WindowsPowerShell, + label: "Windows PowerShell", + description: + "Launch Windows PowerShell in a temporary integrated console for debugging", + }); + } + const launchSelection = await window.showQuickPick( debugConfigPickItems, { placeHolder: "Select a PowerShell debug configuration" }, @@ -440,6 +458,10 @@ export class DebugSessionFeature return PREVENT_DEBUG_START_AND_OPEN_DEBUGCONFIG; } + if (config.sessionName) { + config.createTemporaryIntegratedConsole = true; + } + if (config.attachDotnetDebugger) { return this.resolveAttachDotnetDebugConfiguration(config); } @@ -477,7 +499,10 @@ export class DebugSessionFeature ): Promise { const settings = getSettings(); this.tempDebugProcess = - await this.sessionManager.createDebugSessionProcess(settings); + await this.sessionManager.createDebugSessionProcess( + settings, + session.configuration.sessionName, + ); // TODO: Maybe set a timeout on the cancellation token? const cancellationTokenSource = new CancellationTokenSource(); this.tempSessionDetails = await this.tempDebugProcess.start( diff --git a/src/session.ts b/src/session.ts index 80ab66c81f..df8fd9fbe9 100644 --- a/src/session.ts +++ b/src/session.ts @@ -442,6 +442,7 @@ export class SessionManager implements Middleware { public async createDebugSessionProcess( settings: Settings, + powershellExeName?: string, ): Promise { // NOTE: We only support one temporary Extension Terminal at a time. To // support more, we need to track each separately, and tie the session @@ -455,6 +456,12 @@ export class SessionManager implements Middleware { ); } + const debugPowerShellExeDetails = + powershellExeName === undefined + ? this.PowerShellExeDetails + : ((await this.findPowerShell(powershellExeName)) ?? + this.PowerShellExeDetails); + // TODO: It might not be totally necessary to update the session // settings here, but I don't want to accidentally change this behavior // just yet. Working on getting things to be more idempotent! @@ -462,7 +469,7 @@ export class SessionManager implements Middleware { const bundledModulesPath = await this.getBundledModulesPath(); this.debugSessionProcess = new PowerShellProcess( - this.PowerShellExeDetails.exePath, + debugPowerShellExeDetails.exePath, bundledModulesPath, true, false, @@ -716,7 +723,9 @@ export class SessionManager implements Middleware { ]; } - private async findPowerShell(): Promise { + private async findPowerShell( + wantedName?: string, + ): Promise { this.logger.writeDebug("Finding PowerShell..."); const powershellExeFinder = new PowerShellExeFinder( this.platformDetails, @@ -727,7 +736,7 @@ export class SessionManager implements Middleware { let foundPowerShell: IPowerShellExeDetails | undefined; try { let defaultPowerShell: IPowerShellExeDetails | undefined; - const wantedName = this.sessionSettings.powerShellDefaultVersion; + wantedName ??= this.sessionSettings.powerShellDefaultVersion; if (wantedName !== "") { for await (const details of powershellExeFinder.enumeratePowerShellInstallations()) { // Need to compare names case-insensitively, from https://stackoverflow.com/a/2140723