Skip to content

Commit 99037bc

Browse files
committed
update
1 parent 982f7c3 commit 99037bc

1 file changed

Lines changed: 84 additions & 1 deletion

File tree

  • src/aks-preview/azext_aks_preview/bastion

src/aks-preview/azext_aks_preview/bastion/bastion.py

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import asyncio
77
import os
8+
import shutil
89
import socket
910
import subprocess
1011
import sys
@@ -239,19 +240,99 @@ def _aks_bastion_get_current_shell_cmd():
239240

240241
ppid = os.getppid()
241242
parent = psutil.Process(ppid)
242-
return parent.name()
243+
parent_name = parent.name()
244+
logger.debug(f"Immediate parent process: {parent_name} (PID: {ppid})")
245+
246+
# On Windows, Azure CLI is often invoked as az.cmd, which means the immediate parent
247+
# is cmd.exe but the actual user shell (PowerShell) is the grandparent process
248+
if sys.platform.startswith("win"):
249+
try:
250+
parent_exe = parent.exe()
251+
logger.debug(f"Parent executable path: {parent_exe}")
252+
253+
# If the immediate parent is cmd.exe, check if it's wrapping az.cmd for PowerShell
254+
if "cmd" in parent_name.lower():
255+
try:
256+
# Get the grandparent process (parent of cmd.exe)
257+
grandparent = parent.parent()
258+
if grandparent:
259+
grandparent_name = grandparent.name()
260+
logger.debug(f"Detected grandparent process: {grandparent_name} (PID: {grandparent.pid})")
261+
262+
# If grandparent is PowerShell, that's the actual user shell
263+
if "pwsh" in grandparent_name.lower() or "powershell" in grandparent_name.lower():
264+
logger.debug("Grandparent is PowerShell - using PowerShell as target shell")
265+
# Try to find pwsh first, fall back to powershell
266+
pwsh_path = shutil.which("pwsh")
267+
if pwsh_path:
268+
logger.debug(f"Found pwsh at: {pwsh_path}")
269+
return "pwsh"
270+
powershell_path = shutil.which("powershell")
271+
if powershell_path:
272+
logger.debug(f"Found powershell at: {powershell_path}")
273+
return "powershell"
274+
# If we can't find pwsh/powershell in PATH, use the detected grandparent
275+
logger.debug("PowerShell not found in PATH, using detected grandparent executable")
276+
return grandparent.exe() if grandparent.exe() else grandparent_name
277+
# If grandparent is not PowerShell, stick with cmd
278+
else:
279+
logger.debug("Grandparent is not PowerShell - using cmd as target shell")
280+
return "cmd"
281+
except (psutil.NoSuchProcess, psutil.AccessDenied) as e:
282+
# If we can't access grandparent, assume cmd is the actual shell
283+
logger.debug(f"Cannot access grandparent process: {e} - using cmd as target shell")
284+
return "cmd"
285+
286+
# For direct PowerShell processes (not wrapped by cmd), prefer pwsh over powershell.exe
287+
elif "pwsh" in parent_name.lower() or "powershell" in parent_name.lower():
288+
logger.debug("Direct PowerShell parent detected")
289+
# Try to find pwsh first, fall back to powershell
290+
pwsh_path = shutil.which("pwsh")
291+
if pwsh_path:
292+
logger.debug(f"Found pwsh at: {pwsh_path}")
293+
return "pwsh"
294+
powershell_path = shutil.which("powershell")
295+
if powershell_path:
296+
logger.debug(f"Found powershell at: {powershell_path}")
297+
return "powershell"
298+
# If we can't find pwsh/powershell in PATH, use the detected parent
299+
logger.debug("PowerShell not found in PATH, using detected parent executable")
300+
return parent_exe if parent_exe else parent_name
301+
else:
302+
logger.debug(f"Other Windows shell detected: {parent_name}")
303+
return parent_exe if parent_exe else parent_name
304+
except (psutil.NoSuchProcess, psutil.AccessDenied) as e:
305+
logger.debug(f"Cannot access parent process details: {e}")
306+
pass
307+
308+
logger.debug(f"Using parent process name as shell: {parent_name}")
309+
return parent_name
243310

244311

245312
def _aks_bastion_prepare_shell_cmd(kubeconfig_path):
246313
"""Prepare the shell command to launch a subshell with KUBECONFIG set."""
247314

248315
shell_cmd = _aks_bastion_get_current_shell_cmd()
249316
updated_shell_cmd = shell_cmd
317+
318+
# Handle different shell types
250319
if shell_cmd.endswith("bash") and os.path.exists(os.path.expanduser("~/.bashrc")):
251320
updated_shell_cmd = (
252321
f"""{shell_cmd} -c '{shell_cmd} --rcfile <(cat ~/.bashrc; """
253322
f"""echo "export KUBECONFIG={kubeconfig_path}")'"""
254323
)
324+
elif shell_cmd in ["pwsh", "powershell"] or "pwsh" in shell_cmd.lower() or "powershell" in shell_cmd.lower():
325+
# PowerShell: Set environment variable and start new session
326+
# Use proper PowerShell syntax for setting environment variables
327+
escaped_path = kubeconfig_path.replace("'", "''") # Escape single quotes for PowerShell
328+
if shell_cmd == "pwsh" or "pwsh" in shell_cmd.lower():
329+
updated_shell_cmd = f'pwsh -NoExit -Command "$env:KUBECONFIG=\'{escaped_path}\'"'
330+
else:
331+
updated_shell_cmd = f'powershell -NoExit -Command "$env:KUBECONFIG=\'{escaped_path}\'"'
332+
elif shell_cmd == "cmd" or "cmd" in shell_cmd.lower():
333+
# CMD: Set environment variable and keep session open
334+
updated_shell_cmd = f'cmd /k "set KUBECONFIG={kubeconfig_path}"'
335+
255336
return shell_cmd, updated_shell_cmd
256337

257338

@@ -260,6 +341,8 @@ def _aks_bastion_restore_shell(shell_cmd):
260341

261342
if shell_cmd.endswith("bash"):
262343
subprocess.run(["stty", "sane"], stdin=sys.stdin)
344+
# PowerShell and CMD on Windows typically don't need special restoration
345+
# as they handle terminal state management internally
263346

264347

265348
async def _aks_bastion_launch_subshell(kubeconfig_path, port):

0 commit comments

Comments
 (0)