Bookmark and Share

 

Microsoft Scripting Guy Ed Wilson here. It is Sunday evening in Charlotte, North Carolina, in the United States, which means it is Monday morning on the other side of the world. I was up late last night finishing yesterday’s Weekend Scripter article. My good friend, Jit, found me on Office Communicator, and we chatted for a little while. He is my mentee, and I generally talk to him every month, but he has been gone for the holidays, so I missed talking to him. Not only is he extremely bright, but he had a wife who is an awesome cook and the consummate host. Jit lives in Canberra, Australia, which is a lovely town. Here is a photograph of the National Museum of Australia I took while in Canberra teaching a Windows PowerShell class.

Photograph of National Museum of Australia

 

The Scripting Wife came up to see who I was talking to and joined in our conversation. It was like a family reunion and lots of fun. When we were finished talking, the Scripting Wife looked at the Weekend Scripter article I had written, and said, “That is just about useless. How are they going to run those commands on remote computers?” (Scripting Editor: The Scripting Wife is also responsible for mapping the human genome.)

If you wish to use the Environmental drive on a remote computer, you can use the Invoke-Command cmdlet in Windows PowerShell 2.0 (assuming you have enabled remoting) to easily retrieve the value. This is seen here:

PS C:\> Invoke-Command -computer win7-pc -ScriptBlock { $env:os }
Windows_NT
PS C:\>

One thing to keep in mind with this technique is that if you mistype the environmental variable, you will not receive an error. This is shown here:

PS C:\> Invoke-Command -computer hyperv -ScriptBlock { $env:0s }
PS C:\> Invoke-Command -computer hyperv -ScriptBlock { $env:a }
PS C:\>

When using WMI, it already has the ability to remote, assuming that it is not blocked via the firewall. To use the Win32_Environment WMI class against a remote computer, you only need to add the –computername parameter (or –computer for short) to the Get-WMiObject cmdlet. If you are remoting into an untrusted domain or are logged on using a low-rights account, use the –credential parameter.

PS C:\> Get-wmiobject win32_environment -computer win7-pc | where-object { $_.name -eq 'os' }

VariableValue                           Name                                    UserName
-------------                           ----                                    --------
Windows_NT                              OS                                      <SYSTEM>


PS C:\>

To use the wshEnvironment object from the wshShell object, you will need to use a Windows PowerShell remote session. You can do this directly by using the Enter-PSSession cmdlet and supplying the name of the target computer. This is quick, but does not create a reusable session. When you exit the session, it ends. This is shown here:

PS C:\> Enter-PSSession -ComputerName win7-pc
[win7-pc]: PS C:\Users\ed\Documents> $wshShell = New-Object -ComObject wscript.shell
[win7-pc]: PS C:\Users\ed\Documents> $wshShell.Environment().item("os")
Windows_NT
[win7-pc]: PS C:\Users\ed\Documents> exit
PS C:\>

Using the ExpandEnvironmentStrings method from the WshShell from inside a Windows PowerShell remote session would work exactly the same as using the WshEnvironment object just seen. If you really want to run the command on a single lineperhaps because you wanted to use the Task Scheduleryou would could do it as seen here. Keep in mind that this is a single line of code that would normally wrap. I added the line continuation marks, so the cut-and-paste command would work (if you change the target machine name), but normally I would not use line continuation here:

PS C:\> Invoke-Command -ScriptBlock { (New-Object -ComObject `wscript.shell).ExpandEnvironmentStrings("%os%") } `
-ComputerName win7-pc
Windows_NT
PS C:\>

You might think you could use Invoke-Command and perform the command prompt trick discussed yesterday, but that unfortunately does not work. This is shown here:

PS C:\> Invoke-Command -ScriptBlock { cmd ; set os ; exit } -computer win7-pc
Microsoft Windows [Version 6.1.7600]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:\Users\ed\Documents>
PS C:\>

However, if you use the Enter-PSSession cmdlet, it still does not work. But, who cares, it was simply a trick anyway. No error is generated, it just does not work. This is shown here:

PS C:\> Enter-PSSession -ComputerName win7-pc
[win7-pc]: PS C:\Users\ed\Documents> cmd
Microsoft Windows [Version 6.1.7600]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:\Users\ed\Documents>
[win7-pc]: PS C:\Users\ed\Documents> set os
[win7-pc]: PS C:\Users\ed\Documents> exit
PS C:\>

Using the .NET Framework method to retrieve environmental variables is as simple as using Invoke-Command. Keep in mind that this would normally be a single-line command:

PS C:\> Invoke-Command -ComputerName win7-pc -ScriptBlock `

{ [environment]::GetEnvironmentVariable("os") }

Windows_NT

PS C:\>

If you were really working from the Windows PowerShell command line, you would probably want to use the alias for Invoke-Command (icm) and positional arguments. This shortens the typing and the command considerably, as seen here:

PS C:\> Icm win7-pc { [environment]::GetEnvironmentVariable("os") }

Windows_NT

PS C:\>

As you can see, remoting commands with Windows PowerShell 2.0 is pretty easy, and normally will not involve much additional change to the way you work.

If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at scripter@microsoft.com or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys