ServerManagement.Powershell.psm1

function Copy-PowerShellModuleRemote {
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseUsingScopeModifierInNewRunspaces', '')] # $PSHome is a built in thing
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        $Session,
        [Parameter(Mandatory = $true)]
        [String]$ModuleName
    )
    # 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((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 Module to remote machine'
        Copy-Item "$($localModule.InstalledLocation)\*" -Destination $path -Recurse -ToSession $Session
    }else{
        Write-Output "Module 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 "Module not found after copying..."
    }else{
        Write-Output "Confirmed Module Installation"
    }
}

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
}