Skip to content

Externalize the powershell code? #4

@maxlinc

Description

@maxlinc

I think it might be good to externalize the powershell code rather than embedding it within go. I've been thinking the same thing for a while about https://github.com/WinRb/winrm-fs, so thought I'd start a discussion here.

/cc @sneal because I could have just as easily written this issue on winrb/winrm-fs.

Here's what I'm talking about. The current code has stuff like this:

    script := fmt.Sprintf(`
        $tmp_file_path = [System.IO.Path]::GetFullPath("%s")
        $dest_file_path = [System.IO.Path]::GetFullPath("%s")
        if (Test-Path $dest_file_path) {
            rm $dest_file_path
        }
        else {
            $dest_dir = ([System.IO.Path]::GetDirectoryName($dest_file_path))
            New-Item -ItemType directory -Force -ErrorAction SilentlyContinue -Path $dest_dir | Out-Null
        }
        if (Test-Path $tmp_file_path) {
            $base64_lines = Get-Content $tmp_file_path
            $base64_string = [string]::join("",$base64_lines)
            $bytes = [System.Convert]::FromBase64String($base64_string) 
            [System.IO.File]::WriteAllBytes($dest_file_path, $bytes)
        } else {
            echo $null > $dest_file_path
        }
    `, fromPath, toPath)

I think there would be some benefit to:

  • Creating a powershell function that takes two arguments (e.g. RestoreFile C:\tmp\file.base64 C:\target\file.png)
  • Moving the powershell function out of the go code and into a .ps1 or .psm file
  • Changing the go code so it just loads & invokes the function.

So the final go code would become:

  // Something to load the function
  // This could be as simple as reading the ps1 file and sending the content via WinRM
  // Or could be something like `Install-Module -Name WinRMFileUtils` (see advantages below)
 script := fmt.Sprintf(`RestoreFile "%s" "%s"`, fromPath, toPath)

The advantages are:

  • IMHO makes both the Go code and the PowerShell code more readable. At least if the powershell functions have good, intention-revealing names.
  • Performance (especially when restoring many files):
    • You'll send less bytes over the wire, because you'll only send the function definition once and then invoke it many times, rather than sending a copy of the definition for each file.
    • The Powershell code will be easier to test (e.g. with Pester), benchmark (e.g. with this module) to improve performance.
    • This may also make it easier to batch things on the powershell side, either by implementing a RestoreDir function or sending batches of RestoreFile (e.g. 10 at a time).
  • You'll be able to use proper powershell editors - giving you proper syntax highlighting, autocomplete and/or automated refactoring.
  • It'd be easier to manually test/debug the powershell commands.
  • The powershell could be more easily shared and loaded, possibly as a module that's installable via with other projects, and possibly be installable via PowerShellGet (e.g. Install-Module -Name WinRMFileUtils).
    • This will make it easier to manually test/debug the powershell code.
    • It would also make it easier port or reuse the code in other languages (like winrm/winrm-fs). That means more developers to find (and fix) bugs or performance issues in the powershell code.

I'm not saying you should do all of this right away. The first step would just be moving the powershell code from a .go file into a .ps1 file. That clears the path for things like Pester testing or sharing code with winrm-fs, but doesn't require it.

Thoughts?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions