GoogleCloudPlatform / compute-gpu-installation

Apache License 2.0
77 stars 35 forks source link

Get-WmiObject deprecated and removed in Powershell 6.0+ #13

Closed selborsolrac closed 2 years ago

selborsolrac commented 2 years ago

Describe the bug The Get-WmiObject cmdlet has been removed from Powershell 6.0. This breaks the windows gpu install script on Windows systems that use Powershell 6.0+ because it relies on this now missing cmdlet to find the GPU device information.

https://github.com/GoogleCloudPlatform/compute-gpu-installation/blob/main/windows/install_gpu_driver.ps1#L22

function Find-GPU {
    try {
        (Get-WmiObject -query "select DeviceID from Win32_PNPEntity Where (deviceid Like '%PCI\\VEN_10DE%') and (PNPClass = 'Display' or Name = '3D Video Controller')"  | Select-Object DeviceID -ExpandProperty DeviceID).substring(13,8)
    }
    catch {
        Write-Output "There doesn't seem to be a GPU unit connected to your system. Do you want to continue?"
        Read-Host -Prompt 'Press any key to continue'
    }
}

Environment

To Reproduce Create a GCP instance with one T4 card attached. Use a recent windows server 2019 dc image:

gcloud compute instances create windows-test \
    --project={your project} \
    --zone=us-central1-a \
    --machine-type=n1-standard-4 \
    --subnet=us-central1 \
    --no-address \
    --service-account={your service account}.iam.gserviceaccount.com \
    --scopes=https://www.googleapis.com/auth/cloud-platform \
    --image=windows-server-2019-dc-v20220615 \
    --image-project=windows-cloud \
    --boot-disk-size=150GB \
    --boot-disk-type=pd-ssd \
    --no-shielded-secure-boot \
    --shielded-vtpm \
    --shielded-integrity-monitoring \
    --min-cpu-platform="Intel Haswell" \
    --enable-nested-virtualization \
    --accelerator="type=nvidia-tesla-t4,count=1" \
    --maintenance-policy TERMINATE --restart-on-failure

This image comes with Powershell 7 and Powershell 5 installed on the system. Users that use pwsh for running the windows/install_gpu_driver.ps1 script will launch Powershell 7, which fails when using the Get-WmiObject command. For example:

C:\Users\user> Get-WmiObject -query "select DeviceID from Win32_PNPEntity Where (deviceid Like '%PCI\\VEN_10DE%') and (PNPClass = 'Display' or Name = '3D Video Controller')"
Get-WmiObject: The term 'Get-WmiObject' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

Possible Solution 1 - Minimum supported Powershell version: 3.0

The Get-WmiObject cmdlet has been replaced by Get-CimInstance since Powershell version 3. https://devblogs.microsoft.com/powershell/introduction-to-cim-cmdlets/. The new command could be substituted in but will not work in Powershell 1 or 2:

-  (Get-WmiObject -query "select DeviceID from Win32_PNPEntity Where (deviceid Like '%PCI\\VEN_10DE%') and (PNPClass = 'Display' or Name = '3D Video Controller')"  | Select-Object DeviceID -ExpandProperty DeviceID).substring(13,8)
+  (Get-CimInstance -query "select DeviceID from Win32_PNPEntity Where (deviceid Like '%PCI\\VEN_10DE%') and (PNPClass = 'Display' or Name = '3D Video Controller')"  | Select-Object DeviceID -ExpandProperty DeviceID).substring(13,8)

Possible Solution 2 - Minimum supported Powershell version: 1.0

The Get-CimInstance cmdlet is used only if the Get-WmiObject cmdlet is not available. The cmdlets involved are all available in Powershell 1.0 (i.e. Get-Command and Invoke-Expression)

+  # Determine which management interface to use
+  #
+  # Get-WmiObject is deprecated and removed in Powershell 6.0+  
+  # https://learn.microsoft.com/en-us/powershell/scripting/whats-new/differences-from-windows-powershell?view=powershell-7#cmdlets-removed-from-powershell
+  #
+  # We maintain backwards compabitility with older versions of Powershell by using Get-WmiObject if available
+  function Get-Mgmt-Command {
+      $Command = 'Get-CimInstance'
+      if (Get-Command Get-WmiObject 2>&1>$null) {
+          $Command = 'Get-WmiObject'
+      }
+      return $Command
+  }

   # Check if the GPU exists with Windows Management Instrumentation
   function Find-GPU {
+      $MgmtCommand = Get-Mgmt-Command
       try {
-          (Get-WmiObject -query "select DeviceID from Win32_PNPEntity Where (deviceid Like '%PCI\\VEN_10DE%') and (PNPClass = 'Display' or Name = '3D Video Controller')"  | Select-Object DeviceID -ExpandProperty DeviceID).substring(13,8)
+          $Command = "(${MgmtCommand} -query ""select DeviceID from Win32_PNPEntity Where (deviceid Like '%PCI\\VEN_10DE%') and (PNPClass = 'Display' or Name = '3D Video Controller')"" | Select-Object DeviceID -ExpandProperty DeviceID).substring(13,8)"
+          Invoke-Expression -Command $Command
       }

I'd be happy to submit a PR with whatever changes you think are best.

m-strzelczyk commented 2 years ago

I like the second solution. If you would send us a PR, I'd be happy to review and merge :)

m-strzelczyk commented 2 years ago

Thank you @selborsolrac for contributing a fix for this :) I think we can now close this issue!