PowerShell : Using Windows Remote Management with alternate credentials to retrieve services
As you could see in my last post : My First WinRM PowerShell Script , I started playing with WinRM in this post how to retrieve a list of services on a remote computer, often youcan not do this with your current user account
So we want to connect to a remote server to list the services, and need other credentials First the credentials
we will see there is a helper method for this but I ran into some problems with using it :
PoSH> $wa = New-Object -ComObject Wsman.Automation
PoSH> $wa.c
PoSH> ╔═ $wa.c ══════════════════════╗
PoSH> ║ $wa.CreateConnectionOptions( ║
PoSH> ║ $wa.CreateResourceLocator( ║
PoSH> ║ $wa.CreateSession( ║
PoSH> ║ $wa.CommandLine ║
PoSH> ╚═[1] 1-4 (4/25)]══════════════╝
PoSH> $options = $wa.CreateConnectionOptions()
PoSH> $Options = $wa.CreateConnectionOptions()
PoSH> $options.username = 'foo'
PoSH> $options.Password = 'bar'
Exception setting "Password": "Type mismatch. (Exception from HRESULT: 0x80020005 (DISP_E_TYPEMISMATCH))"
At line:1 char:10
+ $options.P <<<< assword = 'bar'
PoSH>
the problem we can find here : WSMan.CreateSession and here ConnectionOptions
Password
Data type:
BSTRAccess type: Write-only
Sets the password of a local or domain account on the remote computer.
I can see to be able to set it from powerShell, I made the following workaround using the MSScriptControl COM object, to do the same from VbScriptCode that enables me to just throw a string into it :
Function Get-WinRmCredentials ([Management.Automation.PSCredential]$cred = (Get-Credential)) {
$vbs = new-object -com MSScriptControl.ScriptControl
$vbs.language = 'vbscript'
$VBS.ExecuteStatement('Set objWsman = CreateObject( "WSMAN.Automation" )')
$VBS.ExecuteStatement('Set objOptions = objWSMan.CreateConnectionOptions')
$VBS.ExecuteStatement("objOptions.userName = ""$($cred.GetNetworkCredential().username)""")
$VBS.ExecuteStatement("objOptions.Password = ""$($cred.GetNetworkCredential().Password)""")
$VBS.eval('objOptions')
}
This function will take a PSCredential object as input or fires the Get-credential Cmdlet to ask for one So we can ask convert a PowerShell credentials object to an WinRM ConnectionObject where name and password are filled for the PsCredentials object :
PoSH> $rmCred = Get-WinRmCredentials
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
Credential
PoSH> $rmCred
UserName Password
-------- --------
foo
PoSH>
and we can use the returned object to connect to WinRM but what we also is provide a Flag :
We can look at the Object to see what Flags are available and what is there value :
PoSH> $wa.S
PoSH> ╔═ $wa.S ══════════════════════════════╗
PoSH> ║ $wa.SessionFlagCredUsernamePassword( ║
PoSH> ║ $wa.SessionFlagEnableSPNServerPort( ║
PoSH> ║ $wa.SessionFlagNoEncryption( ║
PoSH> ║ $wa.SessionFlagSkipCACheck( ║
PoSH> ║ $wa.SessionFlagSkipCNCheck( ║
PoSH> ║ $wa.SessionFlagUseBasic( ║
PoSH> ║ $wa.SessionFlagUseDigest( ║
PoSH> ║ $wa.SessionFlagUseKerberos( ║
PoSH> ║ $wa.SessionFlagUseNegotiate( ║
PoSH> ║ $wa.SessionFlagUseNoAuthentication( ║
PoSH> ║ $wa.SessionFlagUTF8( ║
PoSH> ╚═[1] 1-11 (11/11)]════════════════════╝
PoSH> $wa.SessionFlagCredUsernamePassword()
4096
PoSH> $wa.CreateSession
MemberType : Method
OverloadDefinitions : {IDispatch CreateSession (string, int, IDispatch)}
TypeNameOfValue : System.Management.Automation.PSMethod
Value : IDispatch CreateSession (string, int, IDispatch)
Name : CreateSession
IsInstance : True
PoSH>
OK the value we need for this flag is 4096
And now we have the helper objects created and have enough information we can connect to the remote computer to list the services for example :
PoSH> $session = $wa.CreateSession('http://longhorn1.poshworks.com',4096,$rmcred) ; $session
Error BatchItems Timeout
----- ---------- -------
-1 -1
PoSH>
PoSH> $ResourceUri = "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_Service"
PoSH> $s= $session.Enumerate($ResourceUri)
PoSH> $services = &{do { ([xml]$s.ReadItem()).win32_service } until ($s.AtEndOfStream)}
PoSH> $services | select -first 5 | ft name,Caption,State
Name Caption State
---- ------- -----
AeLookupSvc Application Experience Running
ALG Application Layer Gateway Service Stopped
AppHostSvc Application Host Helper Service Running
Appinfo Application Information Running
AppMgmt Application Management Running
PoSH>
for WinRM you need use an URI for the WMI path so we create that in first line in the second we get the services.
the 3th line is the workhorse of this script ( or bunch of interactive lines, hmm how you you call that , anyone ? ) :
$services = &{do { ([xml]$s.ReadItem()).win32_service } until ($s.AtEndOfStream)}
this line reads the output from the WinRM call and the same as in the last post I cast the results into XML objects, but this time I a start one level deeper to get rid of the need for using the win32_service property everytime and that enables me to use the PowerShell utilities directly on the resulting collection of XML objects.
you can see how much this interactive working and XML support in PowerShell helps working with WinRM , ok we need to use some embedded Vbscript to set the credentials, but after wrapping that into a function we are ready to go ....
more later about firing some Posh Commands remotely .
Enjoy,
Greetings /\/\o\/\/
PS thanks to Jaykul for help and inspiration