Powershell Invoke-Command does not return correct output
Asked Answered
W

1

2

I'm trying to collect some registry values from remote server using StdRegProv class:

Invoke-Command -ComputerName $ComputerHost -Credential $cred -ScriptBlock { Get-WmiObject -List -Namespace "root\default" | Where-Object { $_.Name -eq "StdRegProv" } }

But it doesnt return methods for these class in output:

   NameSpace: ROOT\default

Name                                Methods              Properties                                                                       PSComputerName
----                                -------              ----------                                                                       --------------
StdRegProv
                                                                                                                              

If i execute the command from ScriptBlock in machine locally, all works fine and output looks like these:

   NameSpace: ROOT\default

Name                                Methods              Properties                                                                                                                                                                                                
----                                -------              ----------                                                                                                                                                                                                
StdRegProv                          {CreateKey, Delet... {}       

Some of other commands, like Get-Service, works ok and i can see the output. What is the problem with these one? Remote machine is: Windows Server 2003 with installed .Net 3.5.1 and PowerShell 2.0

I thought, that StdRegProv class doesnt work in 2003 server, but it works ok locally

Willettewilley answered 30/10, 2023 at 11:7 Comment(3)
Windows Server 2003 and PowerShell 2.0? Plenty of risk there. netcraft.com/blog/…Romish
Same issue in Win 10 22H2 machineWillettewilley
That's the definition of returned serialized objects. No methods.Been
K
1

As an aside:

  • The CIM cmdlets (e.g., Get-CimInstance) superseded the WMI cmdlets (e.g., Get-WmiObject) in Windows PowerShell v3 (released in September 2012). Therefore, the WMI cmdlets should be avoided, not least because PowerShell (Core) 7+, the modern cross-platform success to Windows PowerShell where all future effort will go, doesn't even have them anymore. Note that WMI still underlies the CIM cmdlets, however. For more information, see this answer; the bottom section below shows a CIM solution.

  • Since you're running the - long obsolete - Windows PowerShell v2, the CIM cmdlets are not an option.


You're calling Get-WmiObject via PowerShell remoting (Invoke-Command -ComputerName), which for all but a handful of well-known types involves a loss of type fidelity:

  • Notably, instances of most types are emulated with method-less [psobject] instances that have a static copy of all the (public) properties of the original object - see this answer for details.

This explains why the result object is lacking methods.

You have two options:

  • Either: Call any methods in the remotely executing script block, where the Get-WmiObject output object still has all its original identity.
    For instance, the following command calls the .GetStringValue method to retrieve the data stored in the Path value of registry key HKEY_LOCAL_MACHINE\SOFTWARE\DefaultUserEnvironment on the remote machine:

    Invoke-Command -ComputerName $ComputerHost -Credential $cred -ScriptBlock { 
      (Get-WmiObject -List StdRegProv).GetStringValue(2147483650, 'SOFTWARE\DefaultUserEnvironment', 'Path')
    }
    
  • Or: Use the remoting provided by the WMI cmdlets, in which case there is no loss of type fidelity; however, note that they use a different remoting infrastructure than PowerShell, namely an obsolete DCOM-based one, and may therefore need separate configuration; however, as per your feedback, KB5004442 on caller machines actively prevents use of this infrastructure when targeting machines running older Windows versions.

    # You can call methods such as `.GetStringValue()` directly
    # on the output object.
    (
      Get-WmiObject -ComputerName $ComputerHost -Credential $cred -List StdRegProv
    ).GetStringValue(2147483650, 'SOFTWARE\DefaultUserEnvironment', 'Path')
    

CIM solution (PowerShell v3+)

For the sake of completeness, here is the equivalent solution based on the CIM cmdlets:

$regProv = Get-CimClass StdRegProv -CimSession (New-CimSession -ComputerName $ComputerHost -Credential $cred)
$regProv | Invoke-CimMethod  -MethodName GetStringValue -Arguments @{ hDefKey = [Uint32] 2147483650; sSubKeyName = 'SOFTWARE\DefaultUserEnvironment'; sValueName = 'Path' }

However, you can use just an Invoke-CimMethod call in this case and specify the target class via the -ClassName parameter:

Invoke-CimMethod -ClassName StdRegProv -MethodName GetStringValue -Arguments @{ hDefKey = [Uint32] 2147483650; sSubKeyName = 'SOFTWARE\DefaultUserEnvironment'; sValueName = 'Path' }
  • The CIM cmdlets' remoting uses the same infrastructure as PowerShell's remoting.

  • While there is no loss in type fidelity, note that instances returned by CIM cmdlets do not have .NET methods that you can call directly; instead, CIM methods must be called via the Invoke-CimMethod cmdlet, as shown above.

  • Arguments must be passed via the -Arguments parameter, which requires a hashtable (dictionary) of parameter name-value pairs.

    • The parameter names can be gleaned from the .Parameters property of the .CimClassMethods property available on CIM class instances as returned by Get-CimClass; for CIM instances, as returned by Get-CimInstance, use .CimClass.CimClassMethods; e.g.:

      (Get-CimClass StdRegProv).CimClassMethods | 
        Where Name -eq GetStringValue |
        ForEach Parameters
      
      • This yields the following display output (note that the out-qualified parameter is the output value, returned as part of the result object - see below):

        Name        CimType Qualifiers ReferenceClassName
        ----        ------- ---------- ------------------
        hDefKey      UInt32 {ID, IN}
        sSubKeyName  String {ID, IN}
        sValueName   String {ID, in}
        sValue       String {ID, out}
        
      • Unfortunately, the parameter information does not indicate optional parameters or their default values; e.g., in the case of GetStringValue(), the hDefKey parameter is optional and defaults to HKEY_LOCAL_MACHINE (2147483650)

    • Caveat:

      • Number-typed parameters must be bound by their exact type, hence the [UInt32] cast for the hDefKey parameter above.
  • Results are reported as [pscustomobject] instances[1] with the following properties:

    • .ReturnValue ... the success status of the call; 0 indicates success.
    • .PSComputerName ... the name of the remote computer (if any) from which the result originates
    • .<outParameterName> ... the variably named property corresponding to the method's out parameter name, such as .sValue in the call above.

[1] These instances have an ETS (Extended Type System) type name that reflects the class and method that was invoked, e.g. Microsoft.Management.Infrastructure.CimMethodResult#StdRegProv#GetStringValue, such as reported by Get-Member.

Kim answered 30/10, 2023 at 12:12 Comment(2)
Unfortunately, WMI connection is not an option, coz main machine is windows server 2016 with last DCOM security update KB5004442. These update deny any WMI connections to\from non updated machines and ofc Windows Server 2003 doesn't have these update at all and i havent found workaround to it. These is the main reason why i have to use WinRM here. Regarding "Either" part. Could you please give some example of what u mean, coz it's not clear for me to be honestWillettewilley
Understood, @user21072039; re the "Either" part: please see my update.Kim

© 2022 - 2025 — McMap. All rights reserved.