internal/functions/Copy-Module.ps1
function Copy-Module { <# .SYNOPSIS Copies a module from one computer to another. .DESCRIPTION Copies a module from one computer to another. All transfers done via WinRM / Powershell Remoting. .PARAMETER ModuleName The name of the module to copy. Also accepts a path to the module root folder. .PARAMETER ModuleObject A specific module instance to copy (returned by Get-Module). .PARAMETER FromComputer The computer from which to pick up the module. Localhost by default. Accepts and reuses PSSession objects. .PARAMETER ToComputer The computer(s) on which to install the module. Accepts and reuses PSSession objects. .PARAMETER Credential The credentials to use when connecting to computers. .EXAMPLE PS C:\> Copy-Module -ModuleName BeerFactory -ToComputer server1 Copies the module 'BeerFactory' from localhost to server1 #> [CmdletBinding(DefaultParameterSetName = 'Object')] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'String', Position = 0)] [string[]] $ModuleName, [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'Object')] [PSModuleInfo[]] $ModuleObject, [Parameter(Mandatory = $true)] [PSFComputer[]] $ToComputer, [PSFComputer] $FromComputer = $env:COMPUTERNAME, [PSCredential] $Credential ) begin { $receiveScript = { param ( [string] $Module ) #region Specified a path $uri = [uri]$Module if ($uri.IsFile) { if (-not (Test-Path $Module)) { return [pscustomobject]@{ Module = $Module Success = $false Data = @() } } $sourcePath = "$($Module)\*" $moduleName = (Get-Module $Module -ListAvailable).Name $moduleVersion = (Get-Module $Module -ListAvailable).Version } #endregion Specified a path #region Specified a module name else { $moduleObject = Get-Module $Module | Sort-Object Version -Descending | Select-Object -First 1 if (-not $moduleObject) { return [pscustomobject]@{ Module = $Module Success = $false Data = @() } } $sourcePath = "$($moduleObject.ModuleBase)\*" $moduleName = $moduleObject.Name $moduleVersion = $moduleObject.Version } #endregion Specified a module name #region Gather module object $tempPath = "$($env:TEMP)\$(New-Guid).zip" $workingFolder = New-Item -Path $env:TEMP -Name (New-Guid) -ItemType Directory # Copy item is important, as the zip commands cannot access locked dlls, copy-item can. Copy-Item -Path $sourcePath -Destination $workingFolder.FullName -Recurse Compress-Archive -Path "$($workingFolder.FullName)\*" -DestinationPath $tempPath [pscustomobject]@{ Name = $moduleName Version = $moduleVersion Data = [System.IO.File]::ReadAllBytes($tempPath) Module = $Module Success = $true } Remove-Item $tempPath Remove-Item $workingFolder.FullName -Recurse -Force #endregion Gather module object } $installScript = { param ( $Modules ) #region Update the modules foreach ($module in $Modules) { $installRoot = "$($env:ProgramFiles)\WindowsPowerShell\Modules" if (-not (Test-Path "$($installRoot)\$($module.Name)")) { $null = New-Item -Path $installRoot -Name $module.Name -ItemType Directory -Force } $root = New-Item -Path "$($installRoot)\$($module.Name)" -Name $module.Version -ItemType Directory -Force $tempPath = "$($env:TEMP)\$(New-Guid).zip" [System.IO.File]::WriteAllBytes($tempPath, $Module.Data) Expand-Archive -Path $tempPath -DestinationPath $root.FullName -Force Remove-Item $tempPath } #endregion Update the modules } } process { foreach ($name in $ModuleName) { Write-PSFMessage -String 'Copy-Module.ReceivingModule' -StringValues $FromComputer, $name $module = Invoke-PSFCommand -ComputerName $FromComputer -Credential $Credential -ScriptBlock $receiveScript -ArgumentList $name if (-not $module.Success) { Stop-PSFFunction -String 'Copy-Module.ReceivingModule.Failed' -StringValues $FromComputer, $name -Continue -SilentlyContinue -Cmdlet $PSCmdlet } Write-PSFMessage -String 'Copy-Module.InstallingModule' -StringValues $name, ($ToComputer -join ", ") Invoke-PSFCommand -ComputerName $ToComputer -Credential $Credential -ScriptBlock $installScript -ArgumentList $module } foreach ($object in $ModuleObject) { Write-PSFMessage -String 'Copy-Module.ReceivingModule' -StringValues $FromComputer, $object.ModuleBase $module = Invoke-PSFCommand -ComputerName $FromComputer -Credential $Credential -ScriptBlock $receiveScript -ArgumentList $object.ModuleBase if (-not $module.Success) { Stop-PSFFunction -String 'Copy-Module.ReceivingModule.Failed' -StringValues $FromComputer, $object.ModuleBase -Continue -SilentlyContinue -Cmdlet $PSCmdlet } Write-PSFMessage -String 'Copy-Module.InstallingModule' -StringValues $object.ModuleBase, ($ToComputer -join ", ") Invoke-PSFCommand -ComputerName $ToComputer -Credential $Credential -ScriptBlock $installScript -ArgumentList $module } } } |