diff --git a/Scripts/Save-PowerCLI.ps1 b/Scripts/Save-PowerCLI.ps1 new file mode 100644 index 0000000..e9127bc --- /dev/null +++ b/Scripts/Save-PowerCLI.ps1 @@ -0,0 +1,147 @@ +function Save-PowerCLI { + <# + .SYNOPSIS + Advanced function which can be used to easily download specific versions of PowerCLI from an online gallery + .DESCRIPTION + Downloads a specific version of PowerCLI and all the dependencies at the appropriate version + .NOTES + Author: 1.0 - Dimitar Milov + Author: 2.0 - Kyle Ruddy, @kmruddy + .PARAMETER RequiredVersion + Dynamic parameter used to specify the PowerCLI version + .PARAMETER Path + Directory path where the modules should be downloaded + .PARAMETER Repository + Repository to access the PowerCLI modules + .PARAMETER Simple + Switch used to specify the nested version folders should be removed (therefore adding PowerShell 3/4 compatibility) + .EXAMPLE + Save-PowerCLI -RequiredVersion '10.0.0.7895300' -Path .\Downloads\ + Downloads PowerCLI 10.0.0 to the Downloads folder + .EXAMPLE + Save-PowerCLI -RequiredVersion '6.5.2.6268016' -Path .\Downloads\ -Simple + Downloads PowerCLI 6.5.2 to the Downloads folder and removes the nested version folders + #> + [CmdletBinding(SupportsShouldProcess = $True)] + param( + [Parameter(Mandatory = $true, Position = 1)] + [ValidateScript( { Test-Path $_} )] + $Path, + [Parameter(Mandatory = $false, Position = 2)] + [string]$Repository = 'PSGallery', + [Parameter(Mandatory = $false, Position = 3)] + [Switch]$Simple + ) + DynamicParam + { + # Set the dynamic parameters name + $ParameterName = 'RequiredVersion' + + # Create the dictionary + $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary + + # Create the collection of attributes + $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] + + # Create and set the parameters' attributes + $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute + $ParameterAttribute.ValueFromPipeline = $true + $ParameterAttribute.ValueFromPipelineByPropertyName = $true + $ParameterAttribute.Mandatory = $true + $ParameterAttribute.Position = 0 + + # Add the attributes to the attributes collection + $AttributeCollection.Add($ParameterAttribute) + + # Generate and set the ValidateSet + $pcliVersions = Find-Module -Name 'VMware.PowerCLI' -AllVersions + $arrSet = $pcliVersions | select-Object -ExpandProperty Version + $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet) + + # Add the ValidateSet to the attributes collection + $AttributeCollection.Add($ValidateSetAttribute) + + # Create and return the dynamic parameter + $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection) + $RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter) + return $RuntimeParameterDictionary + } + + begin { + $powercliModuleName = 'VMware.PowerCLI' + $desiredPowerCLIModule = Find-Module -Name $powercliModuleName -RequiredVersion $RequiredVersion -Repository $Repository + + $depsOrder = 'VMware.VimAutomation.Sdk', 'VMware.VimAutomation.Common', 'VMware.Vim', 'VMware.VimAutomation.Cis.Core', 'VMware.VimAutomation.Core', 'VMware.VimAutomation.Nsxt', 'VMware.VimAutomation.Vmc', 'VMware.VimAutomation.Vds', 'VMware.VimAutomation.Srm', 'VMware.ImageBuilder', 'VMware.VimAutomation.Storage', 'VMware.VimAutomation.StorageUtility', 'VMware.VimAutomation.License', 'VMware.VumAutomation', 'VMware.VimAutomation.HorizonView', 'VMware.DeployAutomation', 'VMware.VimAutomation.vROps', 'VMware.VimAutomation.PCloud' + $orderedDependencies = @() + foreach ($depModuleName in $depsOrder) { + $orderedDependencies += $desiredPowerCLIModule.Dependencies | Where-Object {$_.Name -eq $depModuleName} + } + + foreach ($remainingDep in $desiredPowerCLIModule.Dependencies) { + if ($orderedDependencies.Name -notcontains $remainingDep.Name) { + $orderedDependencies += $remainingDep + } + + } + } + + process { + # Save PowerCLI Module Version + $desiredPowerCLIModule | Save-Module -Path $Path + + # Working with the depenent modules + foreach ($dependency in $orderedDependencies) { + if (Get-ChildItem -Path (Join-Path $path $dependency.Name) | Where-Object {$_.Name -ne $dependency.MinimumVersion}) { + # Save dependencies with minimum version + Find-Module $dependency.Name -RequiredVersion $dependency.MinimumVersion | Save-Module -Path $Path + + # Remove newer dependencies version + Get-ChildItem -Path (Join-Path $path $dependency.Name) | Where-Object {$_.Name -ne $dependency.MinimumVersion} | Remove-Item -Confirm:$false -Force -Recurse + } + } + } + + end { + if ($Simple) { + + function FolderCleanup { + param( + [Parameter(Mandatory = $true, Position = 0)] + [ValidateScript( { Test-Path $_} )] + $ParentFolder, + [Parameter(Mandatory = $true, Position = 1)] + [String]$ModuleName, + [Parameter(Mandatory = $true, Position = 2)] + $Version + ) + + + $topFolder = Get-Item -Path (Join-Path $ParentFolder $ModuleName) + $versionFolder = $topFolder | Get-ChildItem -Directory | Where-Object {$_.Name -eq $Version} + $versionFolder | Get-ChildItem | Copy-Item -Destination $topFolder + + # Checking for any nested folders within the PowerCLI module version folder + if ($versionFolder| Get-ChildItem -Directory) { + + # Obtaining and storing the child items to a variable, then copying the items to the parent folder's nested folder + $nestFolder = $versionFolder| Get-ChildItem -Directory + foreach ($nestDir in $nestFolder) { + $nestDir | Get-ChildItem | Copy-Item -Destination (Join-Path $topFolder $nestDir.Name) + } + + } + + # Removing any of the former, no longer needed, directory structure + $versionFolder| Remove-Item -Recurse -Force + } + + FolderCleanup -ParentFolder $Path -ModuleName $desiredPowerCLIModule.Name -Version $desiredPowerCLIModule.Version + foreach ($cleanUp in $orderedDependencies) { + + FolderCleanup -ParentFolder $Path -ModuleName $cleanUp.Name -Version $cleanUp.MinimumVersion + } + + } + + } + } \ No newline at end of file