pywinrm - running New-Mailbox powershell cmdlet remotely
Question: I've been trying to get the [pywinrm](https://pypi.python.org/pypi/pywinrm)
module to run the `New-Mailbox` Powershell cmdlet remotely. This is what I
have so far:

    
    
    import winrm
    
    ps_text = "$pass = ConvertTo-SecureString -String '%s' -AsPlainText -Force; \
                    Add-PSSnapIn Microsoft.Exchange.Management.Powershell.E2010; \
                    New-Mailbox -UserPrincipalName '%s@contoso.lan' \
                    -Alias '%s' -Name '%s' -Password $pass \
                    -Firstname '%s' \
                    -Lastname '%s' \
                    -DisplayName '%s' \
                    -PrimarySmtpAddress '%s'" % \
                    ('password123',
                     'jfd',
                    'john.doe',
                    'John Doe',
                    'John',
                    'Doe',
                    'John Doe',
                    'john.doe@contoso.co.uk')
    
    remote = winrm.Session('https://contoso.co.uk:5986', auth=('ps_remote', 'irrelevant'))
    r = remote_session.run_cmd("powershell", ["-version", "2.0", "-c", ps_text])
    

This is the output I get:

> New-Mailbox : Value cannot be null. Parameter name: serverSettings At line:1
> char:147 \+ $pass = ConvertTo-SecureString -String 'password123'
> -AsPlainText -Force; Add-PSSnapIn
> Microsoft.Exchange.Management.Powershell.E2010; New-Mailbox <<<<
> -UserPrincipalName 'jfd@contoso.lan' -Alias 'john.doe' -Name 'John Doe'
> -Password $pass -Firstname 'John' -Lastname 'Doe' -DisplayName 'John Doe'
> -PrimarySmtpAddress 'john.doe@contoso.co.uk' \+ CategoryInfo : NotSpecified:
> (:) [New-Mailbox], ArgumentNullException \+ FullyQualifiedErrorId :
> System.ArgumentNullException,Microsoft.Exchange.Management.RecipientTasks.NewMailbox

I figure it doesn't like $pass being unquoted, so I then wrap it in single
quotes and get:

> New-Mailbox : Cannot bind parameter 'Password'. Cannot convert the "$pass"
> value of type "System.String" to type "System.Security.SecureString".At
> line:1 char:231 \+ $pass = ConvertTo-SecureString -String 'password123'
> -AsPlainText -Force; Add-PSSnapIn
> Microsoft.Exchange.Management.Powershell.E2010; New-Mailbox
> -UserPrincipalName 'jfd@contoso.lan' -Alias 'john.doe' -Name 'John Doe'
> **-Password <<<< '$pass'** -Firstname 'John' -Lastname 'Doe' -DisplayName
> 'John Doe' -PrimarySmtpAddress 'john.doe@contoso.co.uk' \+ CategoryInfo :
> InvalidArgument: (:) [New-Mailbox], ParameterBindingException \+
> FullyQualifiedErrorId :
> CannotConvertArgumentNoMessage,Microsoft.Exchange.Management.RecipientTasks.NewMailbox

Emphasis mine. And now it interprets it literally instead of expanding the
$pass variable. Is there any way I can get this correctly executed?

Some notes:

  * I'm not using the documented `run_ps` method of `winrm.Session` as it does not run against the correct version of Powershell on the remote side (version 2.0 is required here as that's what the Exchange Management Snap-in requires).
  * I have tried using the low level API of pywinrm as detailed on the package page, but it's no good.
  * If I insert `$pass;` after first line of Powershell, the standard output does actually return `System.Security.SecureString`, which makes it even weirder that it would complain about a null argument in the first example.
  * I have tried wrapping in triple quotes, and swapping quote styles. No dice.
  * I have tried various other methods, including making subprocess calls to a local Powershell to run `New-PSSession` to import the remote session, but this fails to actually get access to the cmdlet I need. I've also tried running script blocks remotely using `Invoke-Command`, but even though that supposedly imports the Snap-in successfully, it doesn't run the actual cmdlet.
  * A pure Python solution would be preferable (hence the use of pywinrm), but I'm open to anything at this stage. Examples of running `New-Mailbox` remotely are pretty sparse, or maybe my Google-fu is weak in this instance.


Answer: In PowerShell, single quotes will prevent variable expansion from occurring.

My recommendation would be:

  * Remove the single quotes from the `$pass`
  * Notice in the error message you posted, that the error is coming from `-serverSettings`, not `-Password`
  * Pass in a value for `-serverSettings` (I couldn't find this parameter in Exchange documentation, but check if it exists or not in your version)
  * Validate the PowerShell command on a Windows system, before attempting to issue the command through `pywinrm`

Hope this helps! Cheers

