远程执行cmdkey脚本权限异常问题排查求助
问题描述
- 本地运行Windows凭据管理PowerShell脚本完全正常,但通过
Invoke-Command远程执行时无任何效果 - 通过
Enter-PSSession手动执行时,脚本交互弹窗正常,但cmdkey /list输出无法写入指定文件,导致脚本失效 - 本地以管理员用户A登录时能看到2条存储凭据,但远程执行
cmdkey /list提示“无存储凭据”;执行cmdkey /delete报错“指定的登录会话不存在”;执行cmdkey /add提示无法通过该启动会话存储凭据 - 确认是权限/会话上下文问题,但不知从何排查
脚本代码
$salidacom = cmdkey /list #FILTRAMOS POR DESTINO/USUARIO $salidacom | Select-String "Destino" | Out-File "C:\InC\p1.txt" -Force $salidacom | Select-String "Usuario" | Out-File "C:\InC\p2.txt" -Force #FILTRAMOS LA SALIDA SERVIDORES $SERVI1 = Get-Content -Path "C:\InC\p1.txt" | Where-Object { $_ -match "X.X.X.X" } $SERVI2 = Get-Content -Path "C:\InC\p1.txt" | Where-Object { $_ -match "Y.Y.Y.Y" } Write-Host "$SERVI1 $SERVI2" $TXTUSU = "C:\InC\p3.txt" $USUSRAW = Get-Content -Path "C:\InC\p2.txt" #FILTRAMOS SOLO LO DE LA DE DERECHA DE USUARIO: $usufilt = 'Usuario: (.+)' #ARRAY PARA GUARDAR LOS USUARIOS $USUCORT = @() foreach ($linea in $USUSRAW) { #MIRAMOS LINEA POR LINEA PARA SACAR CON EL FILTRO if ($linea -match $usufilt) { #SE SACAN LOS USUS $USUTOT = $matches[1] #METEMOS LOS USUARIOS AL ARRAY PARA QUE NOS CUENTE COMO VALORES PARA EXTRAERLO $USUCORT += $USUTOT } } $USUCORT | Out-File -FilePath $TXTUSU -Force #FILTRAMOS LOS USU DE CREDENCIALES ESTABLECEMOS UNA VARIABLE POR USUARIO $USUCORT = Get-Content -Path "C:\InC\p3.txt" | Where-Object { $_ -match "XXXX.COM\\*" } $contador = 1 foreach($USUSOLO IN $USUCORT){ New-Variable -Name "Usu$contador" -Value $USUSOLO -Force $contador++ } Write-Host "$Usu1 $Usu2" Start-Sleep -Seconds 1 #ELIM CREDENCIAL $resp = Read-Host "¿Quieres eliminar la credencial(si/no)?" if ($resp -eq "Si" -or $resp -eq "si") { $serv = Read-host "Dime cual quieres quitar. 1=X.X.X.X 2=Y.Y.Y.Y" if ($serv -eq "1"){ $servidor = "X.X.X.X" cmdkey /delete:$servidor Start-Sleep -Seconds 2 } ----------- #AGREG CREDENCIAL $resp = Read-Host "¿Quieres agregar una credencial(si/no)?" if ($resp -eq "Si" -or $resp -eq "si") { $serv = Read-host "Dime cual de los servidores es el que quieres añadir. 1=X.X.X.X 2=Y.Y.Y.Y" #PARA EL X.X.X.X if ($serv -eq "1"){ $servidor1 = "X.X.X.X" $opc = Read-Host "¿Quieres usar los usuarios que tenia (T) o nuevos (N)?" if ($opc -eq "T" -or $opc -eq "t"){ $usuexist = Read-Host = "Te muestro las credenciales existentes (1)$SERVI1 (2)$SERVI2 | $USUCORT " if ($usuexist -eq 1 ){ $pass = Read-Host -Prompt "Dime la contrasena" -AsSecureString cmdkey /add:$servidor1 /user:$Usu1 /pass:$pass Start-Sleep -Seconds 2 } ----------
问题分析与排查方案
核心原因
PowerShell远程会话(包括Invoke-Command和Enter-PSSession)默认运行在非交互式网络登录会话中,而Windows凭据管理器的凭据是和交互式本地登录会话绑定的。管理员权限无法跨会话上下文生效,因此远程会话既无法访问本地登录用户的凭据,也无法在自身会话中持久化存储凭据。
排查与解决步骤
确认会话类型差异
- 分别在本地和远程会话执行
whoami /logonid,对比登录ID会发现远程会话使用的是网络登录ID,与本地交互式会话完全不同 - 执行
query session查看目标机器会话列表,远程PowerShell会话属于rdp-tcp或console以外的会话类型
- 分别在本地和远程会话执行
切换到交互式远程会话执行脚本
- 使用Sysinternals的
psexec工具,以交互式方式关联目标机器的本地会话启动脚本:psexec \\目标机器IP -i 会话ID powershell -File "C:\路径\你的脚本.ps1" - 会话ID可通过
query session获取,当前登录用户的会话ID通常为1或2
- 使用Sysinternals的
修改脚本避免本地文件依赖
- 远程会话写入
C:\InC目录可能存在权限问题,直接在内存中处理cmdkey /list输出,跳过中间文件:$salidacom = cmdkey /list # 直接过滤目标地址和用户,无需写入文件 $destinos = $salidacom | Select-String "Destino" | Where-Object { $_ -match "X.X.X.X|Y.Y.Y.Y" } $usuarios = $salidacom | Select-String "Usuario: (.+)" | ForEach-Object { $matches[1] } | Where-Object { $_ -match "XXXX.COM\\" }
- 远程会话写入
验证凭据操作的会话上下文
- 在交互式远程会话中执行
cmdkey /list,应能看到与本地登录相同的凭据 - 仅交互式会话支持
cmdkey /add存储持久化凭据,非交互式会话无法完成该操作
- 在交互式远程会话中执行
权限补充检查
- 确认用户A在目标机器上拥有本地管理员权限,且已添加到
本地策略\用户权限分配\允许通过远程桌面服务登录列表中 - 修改注册表禁用UAC远程限制:将
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\LocalAccountTokenFilterPolicy设置为DWORD类型的1,避免管理员权限在远程会话中被降权
- 确认用户A在目标机器上拥有本地管理员权限,且已添加到
内容的提问来源于stack exchange,提问作者AALV8
相关产品推荐
相关产品推荐

