PowerShell возвращает неточные результаты для установленного программного обеспечения при запуске в контексте x86 - PullRequest
0 голосов
/ 09 декабря 2018

Я написал следующий сценарий для проверки имени приложения и возврата некоторых свойств, если оно установлено:

$input = "Microsoft Office Professional"
$appName = "*" + $input + "*"

$responseX64 = Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* |  Where-Object {$_.DisplayName -like $appName} | Select-Object @{Expression={$_.DisplayName + "|" + $_.DisplayVersion +"|x64"}} | Sort-Object -Unique | ft -HideTableHeaders
$responseX86 = Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* |  Where-Object {$_.DisplayName -like $appName} | Select-Object @{Expression={$_.DisplayName + "|" + $_.DisplayVersion +"|x86"}} | Sort-Object -Unique | ft -HideTableHeaders

If (([string]::IsNullOrEmpty($responseX64)) -and ([string]::IsNullOrEmpty($responseX86)))
{
    Write-Output "No matches found."
    exit
}
else 
{
    Write-Output $responseX64
    Write-Output $responseX86
}

Для полноты проверки я проверяю ключи реестра x86 и x64 Uninstall.Это работает, как и ожидалось, когда я запускаю его в сеансе PowerShell x64, и правильно возвращает, что у меня установлена ​​одна версия Microsoft Office x86:

Microsoft Office профессиональный плюс 2016 | 16.0.4266.1001 | x86

Однако, когда я запускаю его на той же машине в сеансе PowerShell x86 (как он будет выполняться моим агентом управления x86), я получаю следующее возвращение:

Microsoft Office профессиональный плюс 2016 | 16.0.4266.1001 | x64

Microsoft Office Professional Plus 2016 | 16.0.4266.1001 | x86

Я дважды проверил записи реестра в разделе HKEY_LOCAL_MACHINE \ SOFTWARE \Microsoft \ Windows \ CurrentVersion \ Uninstall просто для того, чтобы убедиться, что там нет какого-то x64-артефакта Office, но ничего нет.Как я могу изменить этот скрипт, чтобы он возвращал точные результаты при запуске в контексте x86?

Ответы [ 2 ]

0 голосов
/ 09 декабря 2018

Чтобы добавить к правильному ответу @ mklement0, возможно, небольшая тестовая функция может помочь определить разрядность Windows в отличие от текущей разрядности процесса PowerShell:

function Get-Architecture {
    # What architecture does Windows use
    $windowsBitness = switch ([Environment]::Is64BitOperatingSystem) {   # needs .NET 4
        $true  { 64; break }
        $false { 32; break }   
        default { 
            (Get-WmiObject -Class Win32_OperatingSystem).OSArchitecture -replace '\D+', '' 
            # Or do any of these:
            # ((Get-WmiObject -Class Win32_ComputerSystem).SystemType -replace '\D+', '') -replace '86', '32'
            # (Get-WmiObject -Class Win32_Processor).AddressWidth   # slow...
        }
    }

    # What architecture does this PowerShell process use
    $processBitness = [IntPtr]::Size * 8
    # Or do any of these:
    # $processBitness = ($env:PROCESSOR_ARCHITECTURE -replace '\D+]', '') -replace '86', '32'
    # $processBitness = if ([Environment]::Is64BitProcess) { 64 } else { 32 }

    # Return the info as object
    return New-Object -TypeName PSObject -Property @{
        'ProcessArchitecture' = "{0}-bit" -f $processBitness
        'WindowsArchitecture' = "{0}-bit" -f $windowsBitness
    }
}

Возможные значения:

64-битная PowerShell в 64-битной Windows

ProcessArchitecture WindowsArchitecture
------------------- -------------------
64-bit              64-bit

32-битная PowerShell в 64-битной Windows

ProcessArchitecture WindowsArchitecture
------------------- -------------------
32-bit              64-bit

32-битная PowerShell в 32-битной Windows

ProcessArchitecture WindowsArchitecture
------------------- -------------------
32-bit              32-bit
0 голосов
/ 09 декабря 2018

Ваша проблема в том, что для 32-битного процесса , следующие ключевые пути относятся к тому же местоположению, а именно к представлению реестра для 32-битных приложений:

# To both 64- and 32-bit processes: The registry view for 32-bit applications.
HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall

# To 32-bit processes: same as above
# To 64-bit processes: the 64-bit view of the registry.
HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*

Другими словами: ваш код при запуске в 32-битном процессе выполняет одно и то же дважды .


Использование только реестра путь ключа не позволит 32-разрядному процессу видеть 64-разрядный реестр.

Однако есть обходные пути :

  • Вызов 64-разрядного экземпляра PowerShell как внешнего процесса через каталог $env:WinDir\SysNative - см. Ниже.

  • Использование .NETвведите напрямую, как показано в этом ответе .


Вызов 64-битного PowerShell из (32-битного) PowerShell с блоком скриптов { ... } автоматически сериализует выходные объекты 64-битного экземпляра в формате CLIXML, что позволяет вызывающему экземпляру автоматически десериализовать их с разумной точностью [1] , чтобы ваши оригинальные команды фильтрации работали:

# Works only in a 32-bit process.
& $env:WINDIR\SysNative\WindowsPowerShell\v1.0\powershell.exe {
  Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*
} | 
  Where-Object {$_.DisplayName -like $appName} | 
    Select-Object @{Expression={$_.DisplayName + "|" + $_.DisplayVersion +"|x64"}} |
      Sort-Object -Unique

Чтобы определить, выполняется ли ваш сценарий в 32-битном процессе, используйте:

$is32Bit = ${env:ProgramFiles(x86)} -eq ${env:ProgramFiles} -or 
             -not ${env:ProgramFiles(x86)}

-or -not ${env:ProgramFiles(x86)} part обнаруживает случай запуска на чистой 32-битной версии Windows, но обратите внимание, что, очевидно, там нет 64-битных определений.


[1] За исключением нескольких скважинДля известных типов входные объекты десериализуются как [PSCustomObject] экземпляры со статическими свойствами, отражающими значения свойств исходного объекта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...