Issue
I'm trying to work around a bug in Win32-OpenSSH, where -NoProfile -NoLogo
is not respected when using pwsh.exe (Core) and logging in remotely via SSH/SCP. One way (of several) I tried, was to add the following in the very beginning of my Microsoft.PowerShell_profile.ps1
profile.
function IsInteractive {
$non_interactive = '-command', '-c', '-encodedcommand', '-e', '-ec', '-file', '-f'
-not ([Environment]::GetCommandLineArgs() | Where-Object -FilterScript {$PSItem -in $non_interactive})
}
# No point of running this script if not interactive
if (-not (IsInteractive)) {
exit
}
...
However, this didn't work with a remote SSH, because when using [Environment]::GetCommandLineArgs()
with pwsh.exe, all you get back is:
C:\Program Files\PowerShell\6\pwsh.dll
regardless whether or not you are in an interactive session.
Another way I tried, was to scan through the process tree and look for the sshd
parent, but that was also inconclusive, since it may run in another thread where sshd
is not found as a parent.
So then I tried looking for other things. For example conhost
. But on one machine conhost
starts before pwsh
, whereas on another machine, it starts after...then you need to scan up the tree and maybe find an explorer instance, in which case it is just a positive that the previous process is interactive, but not a definite non-interactive current process session.
function showit() {
$isInter = 'conhost','explorer','wininit','Idle',
$noInter = 'sshd','pwsh','powershell'
$CPID = ((Get-Process -Id $PID).Id)
for (;;) {
$PNAME = ((Get-Process -Id $CPID).Name)
Write-Host ("Process: {0,6} {1} " -f $CPID, $PNAME) -fore Red -NoNewline
$CPID = try { ((gwmi win32_process -Filter "processid='$CPID'").ParentProcessId) } catch { ((Get-Process -Id $CPID).Parent.Id) }
if ($PNAME -eq "conhost") {
Write-Host ": interactive" -fore Cyan
break;
}
if ( ($PNAME -eq "explorer") -or ($PNAME -eq "init") -or ($PNAME -eq "sshd") ) {
# Write-Host ": non-interactive" -fore Cyan
break;
}
""
}
}
How can I check if the profile script is running from within a remote SSH session?
Why am I doing this? Because I want to disable the script from running automatically through SSH/SCP/SFTP, while still being able to run it manually (still over SSH.) In Bash this is a trivial one-liner.
Some related (but unhelpful) answers:
- Powershell test for noninteractive mode
- How to check if a Powershell script is running remotely
- Powershell - detect whether running in interactive mode or not (Superuser SO)
Solution
If I understand you correctly, I believe I am handling this particular case in my PowerShell profile by checking the value of [System.Console]::IsOutputRedirected
.
I have a bunch of code in Microsoft.Powershell_profile.ps1
that I want to run only in an interactive session, both when started locally as well as through SSH.
ie. When I run a command over SSH on my remote windows host, like so:
ssh user@winhost C:\\PROGRA~1\PowerShell\7\pwsh.exe -Command Get-ChildItem
This will execute my PowerShell profile Microsoft.Powershell_profile.ps1
automatically before running the Get-ChildItem
command. Inside of my PowerShell profile, I am checking the value of [System.Console]::IsOutputRedirected
which returns true in this case. So when it returns true I return early and skip executing all the logic specific to initializing my interactive PowerShell session (command completion, keybindings, terminal colors, etc).
Conversely, when I SSH into PowerShell on the remote windows host interactively, like so:
ssh user@winhost C:\\PROGRA~1\PowerShell\7\pwsh.exe
This also executes my PowerShell profile Microsoft.Powershell_profile.ps1
automatically before dropping me into an interactive PowerShell session, but in this case, when I check the value of [System.Console]::IsOutputRedirected
it returns false, and I allow the script to continue running to setup my PowerShell profile for an interactive session.
Note: The above logic handles that particular case when it comes to executing over SSH, however, to handle various different possible ways to run PowerShell interactively, I've had to check additional cases. My current logic for handling all possible cases regarding interactivity is the following:
if ([System.Console]::IsOutputRedirected -or ![Environment]::UserInteractive -or !!([Environment]::GetCommandLineArgs() | Where-Object { $_ -ilike '-noni*' })) {
// Non-Interactive
}
See:
Answered By - Cory Gross Answer Checked By - Senaida (WPSolving Volunteer)