Friday, April 10, 2009

Powershell and remote WMI autenthication

In version 1.0 of Windows Power­Shell, gmwi (which is an Alias for Get-WmiObject) is about the only cmdlet that directly supports remote management. This is due mainly to the fact that remote control is built into the underlying Windows Management Instrumentation architecture. And, because Windows PowerShell is simply utilizing that already existing architecture, it’s subject to that architecture’s security features.

Beeing able to perform remote WMI queries is particularly useful when doing a computer inventory for big companies having different domains and forests.

Here’s an example of standard gwmi query:

gwmi -namespace “root\cimv2” -computer $Comp -list

Get-WmiObject : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)) At line:1 char:5

In this instance, I tried to connect to a remote computer called $Comp that I don’t have permission to access. I might, for example, be logged on in a different, untrusted active directory domain, or I could be logged on with a less-privileged account.*

Fortunately, gwmi supports a –credential parameter that allows me to specify an alternate set of user credentials for my WMI connection.

gwmi win32_service –credential mydomain\administrator –computer SComp

My username—is provided in the DOMAIN\Username format.

Note that there’s nowhere you can enter a password. Windows PowerShell will prompt me for that. Windows PowerShell deliberately doesn’t provide a way to enter a password on the command line because doing so would enable you to hardcode passwords into script files, which is an absolute security risk.

However, there are other ways you can work with this –credential parameter

The first one is by creating a sort of credential object, called a PSCredential, ahead of time.

The key is the Get-Credential cmdlet:

$cred = get-credential mydomain\administrator

When I run this, I’m still prompted for the matching password. This time, however, the credential object that is created is stored in the $cred variable. If I look at the contents of $cred, I’ll see the name but not the password:

$cred

UserName

--------

mydomain\administrator

I can then reuse that credential object as much as I like:

gwmi win32_service –credential $cred –computer $Comp

This simplifies repeated WMI connections to a remote computer by predefining a reusable credential object. But I still have to type my password once at the beginning of the script, which is not good if we'd want to schedule the script execution...

The best solution is to previously store the password in a secure file on your disk. Once you store you password, you won't have to enter your credentials over and over again, instead you can just read in your password from the file directly from the script, and create a new PSCredential object from that. Then you can use that credential to perform various unattended administration tasks:

$user = "mydomain\administrator"

$pass = cat securepass.txt | convertto-securestring

$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $user,$pass

For more information on how to store your password in a file, have a look at this post

Please note (and this is very important) that only the person that created the password file can decrypt it. Try it out, log on with different credentials and try getting the password. Thus, even if they have access to the password file, unless they have your credentials, they won't be able to get the password.

2 comments:

  1. I learned a few things from this post. Thanks!

    ReplyDelete
  2. Still having Unauthorised access 0x80070005 executing script on Win 7 to remote vista computer on the same network. Another issue ?

    ReplyDelete