Functions/Install-WSTools.ps1
|
function Install-WSTools { <# .SYNOPSIS Installs/copies the WSTools PowerShell module to a remote computer. .DESCRIPTION Copies the WSTools module from the location specified in the WSTools config file (config.ps1) for UpdatePath to the C:\Program Files\WindowsPowerShell\Modules\WSTools folder on the remote computer. .PARAMETER ComputerName Specifies the name of one or more computers. .EXAMPLE C:\PS>Install-WSTools COMPNAME How to install the WSTools PowerShell module on the remote computer COMPNAME. .EXAMPLE C:\PS>Install-WSTools -ComputerName COMPNAME1,COMPNAME2 How to install the WSTools PowerShell module on the remote computers COMPNAME1 and COMPNAME2. .NOTES Author: Skyler Hart Created: 2018-06-13 14:17:09 Last Edit: 2022-02-19 22:56:29 Keywords: .LINK https://wanderingstag.github.io #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute( "PSUseSingularNouns", "", Justification = "WSTools is the proper name for the module." )] [Diagnostics.CodeAnalysis.SuppressMessageAttribute( "PSAvoidGlobalVars", "", Justification = "Have tried other methods and they do not work consistently." )] [CmdletBinding()] [Alias('Copy-WSTools','Push-WSTools')] Param ( [Parameter( Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [Alias('Host','Name','Computer','CN','common name')] [string[]] $ComputerName = $env:COMPUTERNAME, [Parameter()] [int32]$MaxThreads = 5, [Parameter()] $SleepTimer = 200, [Parameter()] $MaxResultTime = 1200 ) Begin { $config = $Global:WSToolsConfig $app = $config.UpdatePath $appname = "WSTools" $ISS = [system.management.automation.runspaces.initialsessionstate]::CreateDefault() $RunspacePool = [runspacefactory]::CreateRunspacePool(1, $MaxThreads, $ISS, $Host) $RunspacePool.Open() $Code = { [CmdletBinding()] Param ( [Parameter( Mandatory=$true, Position=0 )] [string]$comp, [Parameter( Mandatory=$true, Position=1 )] [string]$app, [Parameter( Mandatory=$true, Position=2 )] [string]$appname ) try { robocopy $app "\\$comp\c$\Program Files\WindowsPowerShell\Modules\$appname" /mir /mt:4 /r:3 /w:15 /njh /njs } catch { # } }#end code block $Jobs = @() } Process { Write-Progress -Activity "Preloading threads" -Status "Starting Job $($jobs.count)" ForEach ($Object in $ComputerName){ $PowershellThread = [powershell]::Create().AddScript($Code) $PowershellThread.AddArgument($Object.ToString()) | out-null $PowershellThread.AddArgument($app.ToString()) | out-null $PowershellThread.AddArgument($appname.ToString()) | out-null $PowershellThread.RunspacePool = $RunspacePool $Handle = $PowershellThread.BeginInvoke() $Job = "" | Select-Object Handle, Thread, object $Job.Handle = $Handle $Job.Thread = $PowershellThread $Job.Object = $Object.ToString() $Jobs += $Job } } End { $ResultTimer = Get-Date While (@($Jobs | Where-Object {$Null -ne $_.Handle}).count -gt 0) { $Remaining = "$($($Jobs | Where-Object {$_.Handle.IsCompleted -eq $False}).object)" If ($Remaining.Length -gt 60){ $Remaining = $Remaining.Substring(0,60) + "..." } Write-Progress ` -Activity "Copying $appname module to computers. Waiting for Jobs - $($MaxThreads - $($RunspacePool.GetAvailableRunspaces())) of $MaxThreads threads running" ` -PercentComplete (($Jobs.count - $($($Jobs | Where-Object {$_.Handle.IsCompleted -eq $False}).count)) / $Jobs.Count * 100) ` -Status "$(@($($Jobs | Where-Object {$_.Handle.IsCompleted -eq $False})).count) remaining - $remaining" ForEach ($Job in $($Jobs | Where-Object {$_.Handle.IsCompleted -eq $True})){ $Job.Thread.EndInvoke($Job.Handle) $Job.Thread.Dispose() $Job.Thread = $Null $Job.Handle = $Null $ResultTimer = Get-Date } If (($(Get-Date) - $ResultTimer).totalseconds -gt $MaxResultTime){ Write-Error "Child script appears to be frozen, try increasing MaxResultTime" Exit } Start-Sleep -Milliseconds $SleepTimer } $RunspacePool.Close() | Out-Null $RunspacePool.Dispose() | Out-Null } } |