Using Python, Winrm and Powershell to Write Files on Windows from Linux

My primary scripting language is Python and we use it to our manage servers. When it comes to Windows we use WinRM and the Python library pywinrm. One use case is the need to write files from linux to the Windows server, say in the example of writing a config file.

The best way to do this is use Powershell’s StreamWriter. According to this blog post, it’s the fastest of the various methods.

In the sample script below I’ve explained some of the tricks to accomplishing this in the comments.


from winrm import Protocol
import base64
address = "10.10.1.12"
transport = "plaintext"
username = "administrator"
password = "ThePassword"
protocol = "http"
port = 5985

endpoint = "%s://%s:%s/wsman" % (protocol, address, port)

conn = Protocol(endpoint=endpoint, transport=transport,
                username=username, password=password)
shell_id = conn.open_shell()

# the text file we want to send
# this could be populated by reading a file from disk instead
# has some special characters, just to prove they won't be a problem
text_file = """this is a multiline file
that contains special characters such as
"blah"
'#@$*&&($}
that will be written
onto the windows box"""

# first part of the powershell script
# streamwriter is the fastest and most efficient way to write a file
# I have found
# notice the @", this is like a "here document" in linux
# or like triple quotes in python and allows for multiline files
# the file will be placed in the home dir of the user that 
# logs into winrm (administrator in this case)
part_1 = """$stream = [System.IO.StreamWriter] "test.txt"
$s = @"
"""

# second part of the powershell script
# the "@ closes the string
# the replace will change the linux line feed to the
# windows carriage return, line feed
part_2 = """
"@ | %{ $_.Replace("`n","`r`n") }
$stream.WriteLine($s)
$stream.close()"""

# join the beginning of the powershell script with the
# text file and end of the ps script
script = part_1 + text_file + part_2

# base64 encode, utf16 little endian. required for windows
encoded_script = base64.b64encode(script.encode("utf_16_le"))

# send the script to powershell, tell it the script is encoded
command_id = conn.run_command(shell_id, "powershell -encodedcommand %s" %
                            (encoded_script))
stdout, stderr, return_code = conn.get_command_output(shell_id, command_id)
conn.cleanup_command(shell_id, command_id)
print "STDOUT: %s" % (stdout)
print "STDERR: %s" % (stderr)

# print the file
command_id = conn.run_command(shell_id, "type test.txt")
stdout, stderr, return_code = conn.get_command_output(shell_id, command_id)
conn.cleanup_command(shell_id, command_id)
print "STDOUT: %s" % (stdout)
print "STDERR: %s" % (stderr)

# delete the file
command_id = conn.run_command(shell_id, "del test.txt")
stdout, stderr, return_code = conn.get_command_output(shell_id, command_id)
conn.cleanup_command(shell_id, command_id)
print "STDOUT: %s" % (stdout)
print "STDERR: %s" % (stderr)

# always good to clean things up, doesn't hurt

 

Advertisements
Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: