asheroto / winget-install

Install winget tool using PowerShell! Prerequisites automatically installed. Works on Windows 10/11 and Server 2019/2022.
https://bit.ly/winget-install
GNU General Public License v3.0
272 stars 33 forks source link

[Bug]: default terminal application and powershell x86 issue #27

Closed uffemcev closed 11 months ago

uffemcev commented 11 months ago

What You Are Seeing?

Another day - another bug :)

If i set default terminal application as windows terminal and run windows powershell (x86) so Get-CurrentProcessModuleName function will stop working because MainModule and Modules fields are empty. Is it the same for you?

I think function must check several properties at once, but not only MainModule.

bug example ``` Windows PowerShell (C) Корпорация Майкрософт (Microsoft Corporation). Все права защищены. Установите последнюю версию PowerShell для новых функций и улучшения! https://aka.ms/PSWindows PS C:\Users\uffemcev> function Get-CurrentProcessModuleName { >> <# >> .SYNOPSIS >> Gets the module name of the current PowerShell process. >> >> .DESCRIPTION >> This function retrieves the window title of the current PowerShell host, finds the corresponding process, and returns the name of the main module of that process without the file extension. >> >> .EXAMPLE >> $processName = Get-CurrentProcessModuleName >> This example shows how to use the function to get the module name of the current process and store it in a variable. >> >> .NOTES >> This function assumes that the window title is unique to the current PowerShell session. If multiple windows have the same title, the function may not behave as expected. >> #> >> >> $windowTitle = $host.ui.RawUI.WindowTitle >> $currentProcess = Get-Process | Where-Object { $_.MainWindowTitle -eq $windowTitle } >> $moduleNameWithExtension = $currentProcess.MainModule.ModuleName >> $moduleNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($moduleNameWithExtension) >> return $moduleNameWithoutExtension >> } PS C:\Users\uffemcev> Get-CurrentProcessModuleName PS C:\Users\uffemcev> $windowTitle = $host.ui.RawUI.WindowTitle PS C:\Users\uffemcev> $currentProcess = Get-Process | Where-Object { $_.MainWindowTitle -eq $windowTitle } PS C:\Users\uffemcev> $currentProcess Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName ------- ------ ----- ----- ------ -- -- ----------- 809 43 92712 82484 0,08 11388 1 WindowsTerminal PS C:\Users\uffemcev> $currentProcess | format-list * Name : WindowsTerminal Id : 11388 PriorityClass : Normal FileVersion : HandleCount : 809 WorkingSet : 84463616 PagedMemorySize : 94937088 PrivateMemorySize : 94937088 VirtualMemorySize : -1 TotalProcessorTime : 00:00:00.0937500 SI : 1 Handles : 809 VM : 4294967295 WS : 84463616 PM : 94937088 NPM : 44152 Path : Company : CPU : 0,09375 ProductVersion : Description : Product : __NounName : Process BasePriority : 8 ExitCode : HasExited : False ExitTime : Handle : 3440 SafeHandle : Microsoft.Win32.SafeHandles.SafeProcessHandle MachineName : . MainWindowHandle : 1574456 MainWindowTitle : Администратор: Windows PowerShell (x86) MainModule : MaxWorkingSet : 1413120 MinWorkingSet : 204800 Modules : ```

System Details

Script verson 3.2.2 Windows 11 22H2 UAC disable Powershell 5.1 Run as administrator

uffemcev commented 11 months ago

Maybe something like this?

function Get-CurrentInterfaceName {
    $windowTitle = $host.ui.RawUI.WindowTitle
    $currentProcess = Get-Process | Where-Object { $_.MainWindowTitle -eq $windowTitle }
    $processMember = get-process | get-member | foreach {($_.Name)}
    $Search = $processMember | foreach {$currentProcess.$_}
    $result = if ($Search -match "WindowsTerminal") {
        "WindowsTerminal"
    } elseif ($Search -match "Conhost") {
        "Conhost"
    } else {
        "Powershell"
    }
    return $result
}
uffemcev commented 11 months ago

I just found out that powershell x86 does not recognize the conhost command. I think there is need to add a check for powershell x86 in x64 systems with [Environment]::Is64BitProcess and [Environment]::Is64BitOperatingSystem. Like that:

if ([Environment]::Is64BitOperatingSystem) {
    if ([Environment]::Is64BitProcess) {
        Start-Process -FilePath "conhost.exe" -ArgumentList "powershell -ExecutionPolicy Bypass -Command &{$command}" -Verb RunAs
    } else {
        Start-Process -FilePath "$env:windir\sysnative\conhost.exe" -ArgumentList "powershell -ExecutionPolicy Bypass -Command &{$command}" -Verb RunAs
    }
} else {
    Start-Process -FilePath "conhost.exe" -ArgumentList "powershell -ExecutionPolicy Bypass -Command &{$command}" -Verb RunAs
}

More about sysnative More about conhost issue

asheroto commented 11 months ago

What about this?

function Get-CurrentProcessModuleName {
    <#
        .SYNOPSIS
            Gets the module name of the current PowerShell process.
        .DESCRIPTION
            This function retrieves the window title of the current PowerShell host, finds the corresponding process, and returns the name of the main module of that process without the file extension.
        .EXAMPLE
            $processName = Get-CurrentProcessModuleName
            This example shows how to use the function to get the module name of the current process and store it in a variable.
        .NOTES
            This function assumes that the window title is unique to the current PowerShell session. If multiple windows have the same title, the function may not behave as expected.
    #>
    $windowTitle = $host.ui.RawUI.WindowTitle
    $currentProcess = Get-Process | Where-Object { $_.MainWindowTitle -eq $windowTitle }
    $moduleNameWithExtension = $currentProcess.MainModule.ModuleName
    $moduleNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($moduleNameWithExtension)
    return $moduleNameWithoutExtension
}
asheroto commented 11 months ago

I just found out that powershell x86 does not recognize the conhost command. I think there is need to add a check for powershell x86 in x64 systems with [Environment]::Is64BitProcess and [Environment]::Is64BitOperatingSystem. Like that:

if ([Environment]::Is64BitOperatingSystem) {
    if ([Environment]::Is64BitProcess) {
        Start-Process -FilePath "conhost.exe" -ArgumentList "powershell -ExecutionPolicy Bypass -Command &{$command}" -Verb RunAs
    } else {
        Start-Process -FilePath "$env:windir\sysnative\conhost.exe" -ArgumentList "powershell -ExecutionPolicy Bypass -Command &{$command}" -Verb RunAs
    }
} else {
    Start-Process -FilePath "conhost.exe" -ArgumentList "powershell -ExecutionPolicy Bypass -Command &{$command}" -Verb RunAs
}

More about sysnative More about conhost issue

Looks good, can add that into the main script in your PR. Will leave the issue open for now until we're done otherwise my poor memory will continue to fail me. Haha.

uffemcev commented 11 months ago

To be same we should probably check against the lowercase name, in case for some reason a version of Windows uses "conhost" instead of "Conhost"

As far as I know, the -match operator is case-insensitive? So $Search -match "Conhost" and $Search -match "conhost" are the same, aren't ?

asheroto commented 11 months ago

Oh I'm sorry you're right, I missed that. I program in several languages and sometimes forget the characteristics of each.

uffemcev commented 11 months ago

What about this?

function Get-CurrentProcessModuleName {
    <#
        .SYNOPSIS
            Gets the module name of the current PowerShell process.
        .DESCRIPTION
            This function retrieves the window title of the current PowerShell host, finds the corresponding process, and returns the name of the main module of that process without the file extension.
        .EXAMPLE
            $processName = Get-CurrentProcessModuleName
            This example shows how to use the function to get the module name of the current process and store it in a variable.
        .NOTES
            This function assumes that the window title is unique to the current PowerShell session. If multiple windows have the same title, the function may not behave as expected.
    #>
    $windowTitle = $host.ui.RawUI.WindowTitle
    $currentProcess = Get-Process | Where-Object { $_.MainWindowTitle -eq $windowTitle }
    $moduleNameWithExtension = $currentProcess.MainModule.ModuleName
    $moduleNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($moduleNameWithExtension)
    return $moduleNameWithoutExtension
}

Still doesn't work if you run powershell x86 via terminal as default app. And it doesn't work with multiple windows with the same names.

image

uffemcev commented 11 months ago

I need more time for testing, then I'll create a pull request.

uffemcev commented 11 months ago

Finally a simple and universal solution! This works with any conditions and with any number of identical windows. Start-sleep 1 is necessary because without it the function sometimes does not work in conhost powershell.

function Get-CurrentProcess {
    $oldTitle = $host.ui.RawUI.WindowTitle
    $tempTitle = (New-Guid).guid
    $host.ui.RawUI.WindowTitle = $tempTitle
    start-sleep 1
    $currentProcess = Get-Process | Where-Object { $_.MainWindowTitle -eq $tempTitle }
    $currentProcess = [PSCustomObject]@{
        Name = $currentProcess.Name
        Id = $currentProcess.Id
    }
    $host.ui.RawUI.WindowTitle = $oldTitle
    return $currentProcess
}
uffemcev commented 11 months ago

So, any thoughts?

asheroto commented 11 months ago

So, any thoughts?

I think that will work but I'll have to look tomorrow. It's 3:40 AM here and I've been busy with work so haven't had a chance to look at the PRs closely but will let you know. 😊

asheroto commented 11 months ago

that's a pretty clever trick! publishing now thanks for your help