A PowerShell script written for Windows PowerShell 5.1 fails under PowerShell 7 with "Get-WmiObject is not recognized", and one of its modules refuses to import at all. What changed between the engines, and what does PowerShell 7 on Windows offer to keep such a module usable?
answer
- one engine dropped whole cmdlet families
- WMI cmdlets gone, standards-based ones remain
- the manifest can refuse the import
- a background 5.1 process does the work
- proxied objects lose their methods
basics
~20 sPowerShell 6 removed the WMI cmdlets in favour of the CIM cmdlets, and modules whose manifest omits Core from CompatiblePSEditions refuse to load. On Windows, Import-Module -UseWindowsPowerShell proxies such a module through a background 5.1 process.
solid answer
~50 sTwo different failures. `Get-WmiObject` and its siblings were removed in PowerShell 6 — the replacement is the CIM cmdlets, so `Get-CimInstance -ClassName Win32_OperatingSystem` does the same job over the same WMI data. The module failure is separate: a module manifest can declare `CompatiblePSEditions`, and PowerShell 7 refuses to import one that does not list `Core`. On Windows you have two escapes. `Import-Module -SkipEditionCheck` forces the import when you believe the module actually works. `Import-Module -UseWindowsPowerShell` instead loads the module in a background Windows PowerShell 5.1 process and gives you proxy commands, so the code genuinely runs on 5.1 while you type in 7. The catch is that results cross the boundary serialized: you get deserialized property bags with no methods. Both are stopgaps — neither exists on Linux or macOS, where no Windows PowerShell is available to proxy to.
code
powershell · 8 lines# PowerShell 7 on Windows: the WMI cmdlets are gone, use the CIM cmdlets
Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object Caption, Version
# A module marked Desktop-only: run it in a background Windows PowerShell 5.1 process
Import-Module -Name ServerManager -UseWindowsPowerShell
# Results arrive serialized: properties survive, methods do not
(Get-CimInstance -ClassName Win32_ComputerSystem).Namego deeper
Recognise that some cmdlets from older scripts no longer exist in PowerShell 7, and know the CIM cmdlets as the current way to query WMI classes on Windows. Check Get-Command before assuming a name is available.
Explain the two distinct causes — commands removed in PowerShell 6, and manifests declaring CompatiblePSEditions without Core — and name -SkipEditionCheck and -UseWindowsPowerShell as the two different escapes with different meanings.
Demonstrate that you weigh the shim's cost: deserialized objects without methods, a per-call cross-process hop, and no equivalent on Linux or macOS. Say when you would proxy, when you would port, and how you track the debt.
Frame it as estate strategy — which Windows-only modules block a fleet-wide move to pwsh, whether to buy time with compatibility shims or fund a port, and how to keep a migration from settling permanently in the half-way state.
## Two failures wearing one costume "My 5.1 script broke on 7" almost always decomposes into *removed commands* and *rejected modules*. They have different causes and different remedies. ## Removed commands PowerShell 6 was a rebuild on a different runtime, and features that were welded to Windows or to .NET Framework did not come along. The notable removals: * **The WMI cmdlets** — `Get-WmiObject`, `Set-WmiInstance`, `Invoke-WmiMethod`, `Register-WmiEvent`, `Remove-WmiObject`. They were already deprecated in favour of the CIM cmdlets, which speak WS-Man/DCOM through the standards-based CIM stack. * **Workflows** (`workflow` keyword), which depended on Windows Workflow Foundation. * **Snap-ins** (`Add-PSSnapin`), the pre-module extensibility model. * **`-ComputerName`** on many cmdlets — the per-cmdlet remoting shortcut was dropped in favour of real remoting. The WMI fix is mechanical: ```powershell # Windows PowerShell 5.1 Get-WmiObject -Class Win32_LogicalDisk # PowerShell 7 (and 5.1 — the CIM cmdlets exist there too) Get-CimInstance -ClassName Win32_LogicalDisk ``` They are not merely renamed. `Get-CimInstance` returns `CimInstance` objects, which are property bags without the WMI object's methods; invoking a method goes through `Invoke-CimMethod` instead of calling `.Method()` on the result. Property names largely match, so filtering and formatting usually port unchanged while anything calling a method needs rework. Note also that WMI itself is a Windows facility — the CIM cmdlets exist in PowerShell 7 on Windows, and querying `Win32_*` classes is not something a Linux host offers. ## Rejected modules A module manifest (`.psd1`) may declare which editions it supports: ```powershell @{ ModuleVersion = '1.0.0' CompatiblePSEditions = @('Desktop') } ``` When PowerShell 7 sees a manifest whose `CompatiblePSEditions` omits `Core`, it refuses the import rather than letting you discover the incompatibility halfway through a production run. Modules with binary assemblies compiled against .NET Framework, or with hard dependencies on removed engine features, genuinely cannot load. ### Escape 1: skip the check ```powershell Import-Module SomeModule -SkipEditionCheck ``` This only suppresses the manifest gate. If the module is *actually* Framework-bound it will still fail, possibly deep inside a call. Use it when you have tested the module and the manifest is merely stale. ### Escape 2: run it where it works ```powershell Import-Module ServerManager -UseWindowsPowerShell ``` This starts a background Windows PowerShell 5.1 process on the local machine, imports the module *there*, and generates proxy functions in your PowerShell 7 session. When you call one, the call is marshalled to the 5.1 process, executed by the real module, and the result comes back. It is the implicit-remoting mechanism pointed at localhost. The consequence is serialization. Objects crossing the boundary are rehydrated as *deserialized* copies: their type names are prefixed `Deserialized.`, their properties survive as static snapshots, and **their methods do not**. Code that does `$svc.Stop()` or relies on a live object updating breaks; code that reads properties, filters and formats generally works. Performance also changes — every call pays a cross-process hop, so tight loops over thousands of items get noticeably slower. ## What none of this does Neither escape exists off Windows. `-UseWindowsPowerShell` needs a local Windows PowerShell 5.1 to proxy to, and there is none on Linux or macOS. A module that reaches for WMI, the registry provider (`HKLM:`), COM, or Windows-only APIs has no shim on those platforms; there is nothing to fall back on. The honest options are: run that work on a Windows host you reach over remoting, or replace the Windows-specific dependency with something portable. ## How to answer this in an interview Name the two causes separately, give the CIM replacement, and present `-UseWindowsPowerShell` as an explicitly temporary bridge with a stated cost (deserialized objects, per-call overhead, Windows-only) rather than a fix. Then say what the real fix is: port the module or move that step to a host that can run it. The senior signal here is treating a compatibility shim as debt you have chosen deliberately and written down, not as the end of the migration.
- Why do objects returned through -UseWindowsPowerShell behave differently from the ones you get in 5.1?Because they cross a process boundary. The module runs in a background Windows PowerShell 5.1 process and results are serialized and rehydrated in your PowerShell 7 session as `Deserialized.*` property bags. Properties survive as a snapshot; methods do not, so `$obj.SomeMethod()` fails. You also pay a marshalling cost per call, which matters in loops.
- When is -SkipEditionCheck the right tool rather than -UseWindowsPowerShell?When the module is pure script, works fine under Core, and only its manifest is stale — `CompatiblePSEditions` lists `Desktop` because nobody updated it. `-SkipEditionCheck` bypasses the gate and you get a normal in-process import with live objects. If the module carries .NET Framework binaries or uses removed engine features, skipping the check just moves the failure later.
- Does any of this help when the script has to run on Linux?No. `-UseWindowsPowerShell` requires a local Windows PowerShell 5.1 process, which does not exist on Linux or macOS, and `-SkipEditionCheck` cannot conjure Windows APIs. Anything depending on WMI, the registry provider, COM or Windows-only modules must either be executed on a Windows host over remoting or rewritten against a portable mechanism.
saying these in an interview costs you the question
- Thinks Get-WmiObject still works in PowerShell 7
- Says the CIM cmdlets are just a rename of the WMI ones
- Assumes -UseWindowsPowerShell works on Linux
- Expects proxied objects to keep their methods
- Treats -SkipEditionCheck as a guarantee the module works