ServerManagement.Powershell.psm1

<#
.Synopsis
    Copies the specified module to the remote session
.Description
    Copies the specified module and any dependencies to the remote session. This emulates the installation of a module but without requiring internet access for the remote machine.
.Example
    Copy-PowerShellModuleRemote -Session $Session -ModuleName Compex.ServerManagement
.Parameter Session
    Remote session to copy the module to
.Parameter ModuleName
    Name of the module to copy
.Parameter Force
    Does not prompt for input and auto copys all dependencies
#>

function Copy-PowerShellModuleRemote {
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseUsingScopeModifierInNewRunspaces', '')] # $PSHome is a built in thing
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        $Session,
        [Parameter(Mandatory = $true)]
        [String]$ModuleName,
        [Parameter(Mandatory = $false)]
        [switch] $Force
    )
    # Validate local module
    # Currently only checking installed modules, if needed we could expand to also check all module locations using Get-Module as a fallback if not found
    $localModule = Get-InstalledModule -Name $ModuleName
    if($null -eq $localModule){
        Throw "The module $ModuleName was not found to be installed on your machine. Please install it first before you try and copy to a remote machine."
    }else {
        Write-Output "Found module $($localModule.Name) with version $($localModule.Version)."
    }

    # Check for Dependencies...
    $dependencies = Get-PowershellModuleDependency -ModuleName $ModuleName
    foreach ($dependency in $dependencies) {
        if($Force -or (Read-Host "The module depends on another module called: $($dependency.Name) would you like to install (y/n)?").ToLower() -eq 'y'){
            Copy-PowerShellModuleRemote -Session $Session -ModuleName $dependency.Name
        }
    }

    # Get Remote Path
    $path = Join-Path -Path (Invoke-Command -Session $Session -ScriptBlock {"$PSHOME\Modules\"}) -ChildPath $localModule.InstalledLocation.Substring($localModule.InstalledLocation.LastIndexOf($ModuleName))

    # Create Remote Directory
    if((Invoke-Command -Session $Session -ScriptBlock {Test-Path -Path $using:path}) -eq $false){
        Write-Output "Creating remote folder: $path"
        Invoke-Command -Session $Session -ScriptBlock {New-Item -Path $using:path -ItemType Directory}

        # Copy to remote machine
        Write-Output "Copying $ModuleName to remote machine"
        Copy-Item "$($localModule.InstalledLocation)\*" -Destination $path -Recurse -ToSession $Session
    }else{
        Write-Output "$ModuleName version $($localModule.Version) folder already found on remote machine, skipping copy.."
    }

    # Validate remote module
    Invoke-Command -Session $Session -ScriptBlock {Import-Module "$using:ModuleName"}
    $remoteModule = Invoke-Command -Session $Session -ScriptBlock {Get-Module "$using:ModuleName"}

    if($null -eq $remoteModule){
        throw "$ModuleName not found after copying..."
    }else{
        Write-Output "Confirmed $ModuleName Installation"
    }
}

<#
.Synopsis
    Returns an array of the module dependencies
.Description
    Returns an array of the module dependencies, includes name and version
.Example
    Get-PowershellModuleDependency -ModuleName Compex.ServerManagement
.Parameter ModuleName
    Name of the module to get dependencies for
#>

function Get-PowershellModuleDependency {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [String]$ModuleName
    )
    # Get Module
    $localModule = Get-InstalledModule -Name $ModuleName
    if($null -eq $localModule){
        Throw "The module $ModuleName was not found to be installed on your machine."
    }

    $manifestFile = Get-ChildItem "$($localModule.InstalledLocation)\*.psd1"
    $manifest = Import-PowerShellDataFile $manifestFile.FullName

    $dependencies = @()
    foreach ($module in $manifest.RequiredModules) {
        $dependencies += New-Object PSObject -Property @{
            Name = $module['ModuleName']
            Version    = $module['ModuleVersion']
        }
    }

    return $dependencies
}