1

I have the following code, It's work when I use directly within powershell:

Get-WmiObject win32_operatingsystem | select @{LABEL=’LastBootUpTime’;EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)

And it returns:

LastBootUpTime
--------------
14/09/2019 10:41:50

But when I use the command within a Powershell script .ps1 with invoke-command the output returns more informations:

LastBootUpTime        PSComputerName RunspaceId                          
--------------        -------------- ----------                          
9/14/2019 10:41:50 AM 192.168.0.20   af08d2d8-c4f1-4f85-9d6c-e3f4ffe475c6

Why this happen?

If possible, I'd like without the header LastBootUpTime too.

Potter
  • 434
  • 8
  • 21
  • 1
    Invoke-Command will always return additional information, in this case where the command was run and the runspace id. – Adil Hindistan Sep 14 '19 at 21:14
  • 1
    As an aside: The CIM cmdlets (e.g., `Get-CimInstance`) superseded the WMI cmdlets (e.g., `Get-WmiObject`) in PowerShell v3 (released in September 2012). Therefore, the WMI cmdlets should be avoided, not least because PowerShell _Core_, where all future effort will go, doesn't even _have_ them anymore. For more information, see [this answer](https://stackoverflow.com/a/54508009/45375). – mklement0 Sep 15 '19 at 19:02

3 Answers3

3

Invoke-Command will always return additional information, in this case where the command was run and the runspace id. You can always get results into a variable and simply print out the property you want.E.g.

$result = invoke-command {your-command}
$result.LastBootUpTime

or for short

(invoke-command {your-command}).LastBootupTime

Note that when you are using wmi, you do not need to necessarily use invoke-command, you can also directly pass -computer parameter to it to run the command against a remote computer:

Get-WmiObject win32_operatingsystem -computer "remote_computer_name"
mklement0
  • 382,024
  • 64
  • 607
  • 775
Adil Hindistan
  • 6,351
  • 4
  • 25
  • 28
  • Nice; worth adding: The WMI cmdlets were superseded by the CIM cmdlets in PowerShell version 3, and, unlike the WMI cmdlets, which use the firewall-unfriendly DCOM remoting, the CIM cmdlets (with the `-ComputerName` and `-CimSession` parameters) use the same firewall-friendly remoting transport as PowerShell's general-purpose remoting. On a minor note: `Invoke-Command` only decorates the output objects when actual remoting is involved (with `-ComputerName` or `-Session[Name]` arguments - though there's rarely a good reason to use `Invoke-Command` for local execution). – mklement0 Sep 15 '19 at 18:29
2

Since you're ultimately only interested in the (transformed) property value, there's no need to use Select-Object (whose alias is select) at all - use ForEach-Object instead:

Get-WmiObject Win32_OperatingSystem |
  ForEach-Object { $_.ConvertToDateTime($_.LastBootUpTime) }

Note: The extra properties you saw, added by a remote Invoke-Command call with a -ComputerName argument (described below), are still technically present on the result, but they won't display.

That said, the WMI cmdlets were deprecated in PowerShell version 3. Using Get-CimInstance in lieu of Get-WmiObject actually makes the .ConvertToDateTime() call unnecessary (the .LastBootUpTime now directly contains a [datetime] instance), in which case you can simply use Select-Object's -ExpandProperty parameter in order to return the property value only (rather than a [pscustomobject] instance with the requested property):

Get-CimInstance CIM_OperatingSystem | Select-Object -ExpandProperty LastBootUpTime

Note: Get-CimInstance directly supports a -ComputerName argument, so you don't need Invoke-Command -ComputerName for the invocation; unlike the firewall-unfriendly DCOM protocol that the WMI cmdlets use, the CIM cmdlets use the same, firewall-friendly transport as PowerShell remoting.

Or, more succinctly and efficiently, especially in a case such as this where the command returns only a single object, use direct property access:

(Get-CimInstance CIM_OperatingSystem).LastBootUpTime

This answer contrasts the pros and cons of these two approaches and shows other alternatives.


As for what you tried, which generally relates to:

Managing the origin properties automatically added by remote operations:

In remoting scenarios, PowerShell decorates the objects returned with additional properties that provide origin information. These properties are (mostly) of type NoteProperty and are added:

  • when PowerShell remoting is involved - such as via Invoke-Command -ComputerName in your case.

  • when CIM cmdlets such as Get-CimInstance are directly used remotely, such as with the
    -ComputerName parameter.

These properties are:

  • .PSComputerName (the name of the remote computer on which the code was executed)

    • Note: On objects returned from remote CIM calls, .PSComputerName appears as a regular property (type Property), not a NoteProperty.
  • The associated hidden .PSShowComputerName property, which defaults to $true, which explains why you saw a PSComputerName column in the display output.

    • If you capture the objects before printing them to the screen, you can set the property to $false on them, in which case their .PSComputerName property won't show (but will still be there) - however, the .RunspaceId property may - situationally - still show, and would have to be explicitly excluded - see below.
  • PowerShell remoting only (not remote CIM calls): .RunspaceId (the ID of the remote runspace)

To exclude these from local display / presence on the object, use the following techniques:

  • If you're only interested in select properties, make the Select-Object call locally, which, by virtue of locally constructing new [pscustomobject] instances with the properties of interest only, implicitly excludes the remoting-added properties:
Invoke-Command -ComputerName ... { ... } |
  Select-Object Name, LastBootUpTime  # LOCAL call to Select-Object
  • If you're interested in all properties except the remoting-added ones, use
    Select-Object -ExcludeProperty to eliminate them explicitly:
# Get remote output, then locally exclude the remoting-added properties.
Invoke-Command -ComputerName ... { ... } |
  Select-Object * -ExcludeProperty PSComputerName, PSShowComputerName, RunSpaceId

Note: Select-Object generally returns [pscustomobject] instances whose properties are static copies of the input objects and which lack the input type's methods.

mklement0
  • 382,024
  • 64
  • 607
  • 775
0

I found one way! if someone to need here is:

Get-WmiObject win32_operatingsystem | select @{LABEL=’LastBootUpTime’;EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)}}|Select-Object -ExpandProperty  lastbootuptime

Here is how I used (I'm creating a report in HTML for my database)

write-output "<p> Horario do Ultimo boot: $(Get-WmiObject win32_operatingsystem | select @{LABEL=’LastBootUpTime’;EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)}}|Select-Object -ExpandProperty  lastbootuptime)</p>"

The output was (in my language and region):

Horario do Ultimo boot: 09/14/2019 10:41:50
Potter
  • 434
  • 8
  • 21
  • That works, but is inefficient (and verbose, with duplication); you can do without `Select-Object` altogether, if all you're interested in is the _value_ of the `$_.ConvertToDateTime($_.lastbootuptime)` method call: simply use `ForEach-Object` instead: `Get-WmiObject win32_operatingsystem | ForEach-Object { $_.ConverttoDateTime($_.lastbootuptime) }`. – mklement0 Sep 15 '19 at 18:37