functions/Copy-DryADModulesToRemoteTarget.ps1
using NameSpace System.Management.Automation using NameSpace System.Management.Automation.Runspaces <# This is an AD Config module for use with DryDeploy, or by itself. Copyright (C) 2021 Bjørn Henrik Formo (bjornhenrikformo@gmail.com) LICENSE: https://raw.githubusercontent.com/bjoernf73/dry.module.ad/main/LICENSE This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #> function Copy-DryADModulesToRemoteTarget { [CmdletBinding()] param ( [Parameter(Mandatory)] [PSSession]$PSSession, [Parameter(Mandatory)] [string]$RemoteRootPath, [Parameter()] [array]$Modules, [Parameter()] [array]$Folders, [Parameter(HelpMessage = 'Remove the remote root before copy')] [switch]$Force ) try { # While copying multiple tiny files, the progress bar is flickering and not informative at all, so suppress it $OriginalProgressPreference = $ProgressPreference $ProgressPreference = 'SilentlyContinue' if ($Force) { $InvokeDirParams = @{ ScriptBlock = $DryAD_SB_RemoveAndReCreateDir Session = $PSSession ArgumentList = @($RemoteRootPath) } $DirResult = Invoke-Command @InvokeDirParams switch ($DirResult) { $true { olad d 'Created remote directory', "$RemoteRootPath" } { $DirResult -is [ErrorRecord] } { olad w 'Unable to create remote directory', "$RemoteRootPath" $PSCmdlet.ThrowTerminatingError($DirResult) } default { throw "Unable to create remote directory: $($DirResult.ToString())" } } } foreach ($Module in $Modules) { [PSModuleInfo]$ModuleObj = Get-Module -Name $Module -ListAvailable -ErrorAction Stop if ($null -eq $ModuleObj) { throw "Unable to find module '$Module'" } else { $ModuleFolder = Split-Path -Path $ModuleObj.Path try { [system.version](Split-Path -Path $ModuleFolder -Leaf) | Out-Null olad v "Module '$Module' is a versioned module, it's root folder must be: '$(Split-Path -Path $ModuleFolder)'" $ModuleFolder = Split-Path -Path $ModuleFolder } catch { olad v "Module '$Module' is not a versioned module, it's root folder must be: '$ModuleFolder'" } $CopyItemsParams = @{ Path = $ModuleFolder Container = $true Destination = Join-Path -Path $RemoteRootPath -ChildPath $(Split-Path -Path $ModuleFolder -Leaf) ToSession = $PSSession Recurse = $true Force = $true } olad d @("Copying module to '$($PSSession.ComputerName)'", "'$ModuleFolder'") Copy-Item @CopyItemsParams } } foreach ($ModuleFolder in $Folders) { try { [system.io.directoryinfo]$ModuleObj = Get-Item -Name $ModuleFolder -ErrorAction Stop $CopyItemsParams = @{ Path = $ModuleFolder Destination = $RemoteRootPath ToSession = $PSSession Recurse = $true Force = $true } olad d @("Copying module to '$($PSSession.ComputerName)'", "'$ModuleFolder'") Copy-Item @CopyItemsParams } catch { throw "Failed to copy '$ModuleFolder' to remote target" } } # Add RemoteRootPath to $env:PSModulePath on the remote system, so functions are # available without explicit import. Prepare $RemoteRootPath and a $RemoteRootPathRegex # that allows us to test if the path is already added or not. # Change double backslash to single, remove trailing backslash, and lastly make all # single backslashes double in the regex $RemoteRootPath = ($RemoteRootPath.Replace('\\', '\')).TrimEnd('\') $RemoteRootPathRegEx = $RemoteRootPath.Replace('\', '\\') $InvokePSModPathParams = @{ ScriptBlock = $DryAD_SB_PSModPath Session = $PSSession ArgumentList = @($RemoteRootPath, $RemoteRootPathRegEx) } $RemotePSModulePaths = Invoke-Command @InvokePSModPathParams olad d @('The PSModulePath on remote system', "'$RemotePSModulePaths'") switch ($RemotePSModulePaths) { { $RemotePSModulePaths -Match $RemoteRootPathRegEx } { olad v @('Successfully added to remote PSModulePath', "'$RemoteRootPath'") } default { olad w @('Failed to add path to remote PSModulePath', "'$RemoteRootPath'") throw "The RemoteRootPath '$RemoteRootPath' was not added to the PSModulePath in the remote session" } } if ($Force) { $ImportModsParams = @{ Session = $PSSession ScriptBlock = $DryAD_SB_ImportMods ArgumentList = @($Modules) ErrorAction = 'Stop' } $ImportResult = Invoke-Command @ImportModsParams switch ($ImportResult) { $true { olad s "Modules were imported into the session" olad v "The modules '$Modules' were imported into PSSession to $($PSSession.ComputerName)" } default { olad f "Modules were not imported into the session" olad w "The modules '$Modules' were not imported into PSSession to $($PSSession.ComputerName)" throw "The modules '$Modules' were not imported into PSSession to $($PSSession.ComputerName)" } } } } catch { $PSCmdlet.ThrowTerminatingError($_) } finally { $ProgressPreference = $OriginalProgressPreference } } |