From 754e9300ebdf49c417d67de8732f2baa6919804c Mon Sep 17 00:00:00 2001 From: mtelvers Date: Mon, 16 Oct 2017 10:03:30 +0100 Subject: [PATCH 01/28] Updates to New-HVPool Removed parameter -Deleting which isn't used and is a read-only property anyway Corrected automatic Logoff Minutes validation range which is 1.. rather than 1..120 Updated the validation set for delete or refresh machines after log off. From the API, valid options are Never, Delete, Refresh not Never, Delete, After Allowed selecting the AD Container when creating Linked Clones --- Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 b/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 index 058f979..25c64a5 100644 --- a/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 +++ b/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 @@ -3568,10 +3568,6 @@ function New-HVPool { [string[]] $ConnectionServerRestrictions, - #desktopSpec.desktopSettings.deleting - [Parameter(Mandatory = $false,ParameterSetName = "LINKED_CLONE")] - [boolean]$Deleting = $false, - #desktopSpec.desktopSettings.logoffSettings.powerPloicy [Parameter(Mandatory = $false,ParameterSetName = "LINKED_CLONE")] [ValidateSet('TAKE_NO_POWER_ACTION', 'ALWAYS_POWERED_ON', 'SUSPEND', 'POWER_OFF')] @@ -3584,7 +3580,7 @@ function New-HVPool { #desktopSpec.desktopSettings.logoffSettings.automaticLogoffMinutes [Parameter(Mandatory = $false,ParameterSetName = "LINKED_CLONE")] - [ValidateRange(1,120)] + [ValidateRange(1,[int]::MaxValue)] [int]$AutomaticLogoffMinutes = 120, #desktopSpec.desktopSettings.logoffSettings.allowUsersToResetMachines @@ -3597,7 +3593,7 @@ function New-HVPool { #desktopSpec.desktopSettings.logoffSettings.deleteOrRefreshMachineAfterLogoff [Parameter(Mandatory = $false,ParameterSetName = "LINKED_CLONE")] - [ValidateSet('NEVER', 'DELETE', 'AFTER')] + [ValidateSet('NEVER', 'DELETE', 'REFRESH')] [string]$deleteOrRefreshMachineAfterLogoff = 'NEVER', #desktopSpec.desktopSettings.logoffSettings.refreshOsDiskAfterLogoff @@ -3961,8 +3957,9 @@ function New-HVPool { [int] $NumUnassignedMachinesKeptPoweredOn = 1, - #desktopSpec.automatedDesktopSpec.customizationSettings.cloneprepCustomizationSettings.instantCloneEngineDomainAdministrator if INSTANT_CLONE + #desktopSpec.automatedDesktopSpec.customizationSettings.AdContainer [Parameter(Mandatory = $false,ParameterSetName = 'INSTANT_CLONE')] + [Parameter(Mandatory = $false,ParameterSetName = 'LINKED_CLONE')] $AdContainer = 'CN=Computers', [Parameter(Mandatory = $true,ParameterSetName = 'INSTANT_CLONE')] From ba61e6bb0f9349ccd9c610af2ca134e59650d98e Mon Sep 17 00:00:00 2001 From: mtelvers Date: Mon, 16 Oct 2017 19:11:49 +0100 Subject: [PATCH 02/28] Updated Find-HVMachine Updated Find-HVMachine to use the iterative query service, QueryService_Create() rather than the quick QueryService_Query() --- .../VMware.Hv.Helper/VMware.HV.Helper.psm1 | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 b/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 index 25c64a5..6953824 100644 --- a/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 +++ b/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 @@ -6794,25 +6794,35 @@ function Find-HVMachine { $andFilter.Filters = $filterset $query.Filter = $andFilter } - $queryResults = $query_service_helper.QueryService_Query($services,$query) - $machineList = $queryResults.results + $machineList = @() + $queryResults = $query_service_helper.QueryService_Create($services, $query) + do { + if ($machineList.length -ne 0) { $queryResults = $query_service_helper.QueryService_GetNext($services, $queryResults.id) } + $machineList += $queryResults.results + } while ($queryResults.remainingCount -gt 0) + $query_service_helper.QueryService_Delete($services, $queryResults.id) } if ($wildcard -or [string]::IsNullOrEmpty($machineList)) { $query.Filter = $null - $queryResults = $query_service_helper.QueryService_Query($services,$query) - $strFilterSet = @() - foreach ($setting in $machineSelectors.Keys) { - if ($null -ne $params[$setting]) { - if ($wildcard -and (($setting -eq 'MachineName') -or ($setting -eq 'DnsName')) ) { - $strFilterSet += '($_.' + $machineSelectors[$setting] + ' -like "' + $params[$setting] + '")' - } else { - $strFilterSet += '($_.' + $machineSelectors[$setting] + ' -eq "' + $params[$setting] + '")' + $machineList = @() + $queryResults = $query_service_helper.QueryService_Create($services,$query) + do { + if ($machineList.length -ne 0) { $queryResults = $query_service_helper.QueryService_GetNext($services, $queryResults.id) } + $strFilterSet = @() + foreach ($setting in $machineSelectors.Keys) { + if ($null -ne $params[$setting]) { + if ($wildcard -and (($setting -eq 'MachineName') -or ($setting -eq 'DnsName')) ) { + $strFilterSet += '($_.' + $machineSelectors[$setting] + ' -like "' + $params[$setting] + '")' + } else { + $strFilterSet += '($_.' + $machineSelectors[$setting] + ' -eq "' + $params[$setting] + '")' + } } } - } - $whereClause = [string]::Join(' -and ', $strFilterSet) - $scriptBlock = [Scriptblock]::Create($whereClause) - $machineList = $queryResults.results | where $scriptBlock + $whereClause = [string]::Join(' -and ', $strFilterSet) + $scriptBlock = [Scriptblock]::Create($whereClause) + $machineList += $queryResults.results | where $scriptBlock + } while ($queryResults.remainingCount -gt 0) + $query_service_helper.QueryService_Delete($services, $queryResults.id) } return $machineList } From 1edf24432c3d4257351641d07b40afa4a4050bd7 Mon Sep 17 00:00:00 2001 From: mtelvers Date: Wed, 18 Oct 2017 08:54:42 +0100 Subject: [PATCH 03/28] Improved searching for Host and Clusters, Resource Pools and Access Groups Add three new internal functions Get-HVHostOrClusterID, Get-HVResourcePoolID and Get-HVAccessGroupID to search the tree results of HostOrCluster_GetHostOrClusterTree(), ResourcePool_GetResourcePoolTree() and AccessGroup_List() respectively. Previously only the top level of the result tree from these calls where considered which was raised as issue #88. The solutions provided in the discussions were point fixes as they changed the level of the tree which was searched which missed matches at the other and the original levels. --- .../VMware.Hv.Helper/VMware.HV.Helper.psm1 | 162 +++++++++++++++--- 1 file changed, 138 insertions(+), 24 deletions(-) diff --git a/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 b/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 index 6953824..dd7a66c 100644 --- a/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 +++ b/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 @@ -2646,8 +2646,7 @@ function New-HVFarm { $farmData = $farmSpecObj.data $AccessGroup_service_helper = New-Object VMware.Hv.AccessGroupService - $ag = $AccessGroup_service_helper.AccessGroup_List($services) | Where-Object { $_.base.name -eq $accessGroup } - $farmData.AccessGroup = $ag.id + $farmData.AccessGroup = Get-HVAccessGroupID $AccessGroup_service_helper.AccessGroup_List($services) $farmData.name = $farmName $farmData.DisplayName = $farmDisplayName @@ -2851,21 +2850,17 @@ function Get-HVFarmProvisioningData { } if ($hostOrCluster) { $HostOrCluster_service_helper = New-Object VMware.Hv.HostOrClusterService - $hostClusterList = ($HostOrCluster_service_helper.HostOrCluster_GetHostOrClusterTree($services, $vmobject.datacenter)).treeContainer.children.info - $HostClusterObj = $hostClusterList | Where-Object { $_.name -eq $hostOrCluster } - if ($null -eq $HostClusterObj) { - throw "No host or cluster found with name: [$hostOrCluster]" + $vmObject.HostOrCluster = Get-HVHostOrClusterID $HostOrCluster_service_helper.HostOrCluster_GetHostOrClusterTree($services,$vmobject.datacenter) + if ($null -eq $vmObject.HostOrCluster) { + throw "No hostOrCluster found with Name: [$hostOrCluster]" } - $vmObject.HostOrCluster = $HostClusterObj.id } if ($resourcePool) { $ResourcePool_service_helper = New-Object VMware.Hv.ResourcePoolService - $resourcePoolList = $ResourcePool_service_helper.ResourcePool_GetResourcePoolTree($services, $vmobject.HostOrCluster) - $resourcePoolObj = $resourcePoolList | Where-Object { $_.resourcepooldata.name -eq $resourcePool } - if ($null -eq $resourcePoolObj) { - throw "No resource pool found with name: [$resourcePool]" + $vmObject.ResourcePool = Get-HVResourcePoolID $ResourcePool_service_helper.ResourcePool_GetResourcePoolTree($services,$vmobject.HostOrCluster) + if ($null -eq $vmObject.ResourcePool) { + throw "No Resource Pool found with Name: [$resourcePool]" } - $vmObject.ResourcePool = $resourcePoolObj.id } return $vmObject } @@ -4620,8 +4615,7 @@ function New-HVPool { } if (!$desktopBase) { $accessGroup_client = New-Object VMware.Hv.AccessGroupService - $ag = $accessGroup_client.AccessGroup_List($services) | Where-Object { $_.base.name -eq $accessGroup } - $desktopSpecObj.base.AccessGroup = $ag.id + $desktopSpecObj.base.AccessGroup = Get-HVAccessGroupID $accessGroup_client.AccessGroup_List($services) } else { $desktopSpecObj.base = $desktopBase } @@ -4811,25 +4805,146 @@ function Get-HVPoolProvisioningData { } if ($hostOrCluster) { $vmFolder_helper = New-Object VMware.Hv.HostOrClusterService - $hostClusterList = ($vmFolder_helper.HostOrCluster_GetHostOrClusterTree($services,$vmobject.datacenter)).treeContainer.children.info - $hostClusterObj = $hostClusterList | Where-Object { ($_.path -eq $hostOrCluster) -or ($_.name -eq $hostOrCluster) } - if ($null -eq $hostClusterObj) { + $vmObject.HostOrCluster = Get-HVHostOrClusterID $vmFolder_helper.HostOrCluster_GetHostOrClusterTree($services,$vmobject.datacenter) + if ($null -eq $vmObject.HostOrCluster) { throw "No hostOrCluster found with Name: [$hostOrCluster]" } - $vmObject.HostOrCluster = $hostClusterObj.id } if ($resourcePool) { $resourcePool_helper = New-Object VMware.Hv.ResourcePoolService - $resourcePoolList = $resourcePool_helper.ResourcePool_GetResourcePoolTree($services,$vmobject.HostOrCluster) - $resourcePoolObj = $resourcePoolList | Where-Object { ($_.resourcepooldata.path -eq $resourcePool) -or ($_.resourcepooldata.name -eq $resourcePool) } - if ($null -eq $resourcePoolObj) { - throw "No hostOrCluster found with Name: [$resourcePool]" + $vmObject.ResourcePool = Get-HVResourcePoolID $resourcePool_helper.ResourcePool_GetResourcePoolTree($services,$vmobject.HostOrCluster) + if ($null -eq $vmObject.ResourcePool) { + throw "No Resource Pool found with Name: [$resourcePool]" } - $vmObject.ResourcePool = $resourcePoolObj.id } return $vmObject } + +function Get-HVHostOrClusterID { +<# +.Synopsis + Recursive search for a Host or Cluster name within the results tree from HostOrCluster_GetHostOrClusterTree() and returns the ID + +.NOTES + HostOrCluster_GetHostOrClusterTree() returns a HostOrClusterTreeNode as below + + HostOrClusterTreeNode.container $true if this is a container + HostOrClusterTreeNode.treecontainer HostOrClusterTreeContainer + HostOrClusterTreeNode.treecontainer.name Container name + HostOrClusterTreeNode.treecontainer.path Path to this container + HostOrClusterTreeNode.treecontainer.type DATACENTER, FOLDER or OTHER + HostOrClusterTreeNode.treecontainer.children HostOrClusterTreeNode[] list of child nodes with potentially more child nodes + HostOrClusterTreeNode.info HostOrClusterInfo + HostOrClusterTreeNode.info.id Host or cluster ID + HostOrClusterTreeNode.info.cluster Is this a cluster + HostOrClusterTreeNode.info.name Host or cluster name + HostOrClusterTreeNode.info.path Path to host or cluster name + HostOrClusterTreeNode.info.virtualCenter + HostOrClusterTreeNode.info.datacenter + HostOrClusterTreeNode.info.vGPUTypes + HostOrClusterTreeNode.info.incompatibileReasons + + Author : Mark Elvers +#> + param( + [Parameter(Mandatory = $true)] + [VMware.Hv.HostOrClusterTreeNode]$hoctn + ) + if ($hoctn.container) { + foreach ($node in $hoctn.treeContainer.children) { + $id = Get-HVHostOrClusterID $node + if ($id -ne $null) { + return $id + } + } + } else { + if ($hoctn.info.path -eq $hostOrCluster -or $hoctn.info.name -eq $hostOrCluster) { + return $hoctn.info.id + } + } + return $null +} + +function Get-HVResourcePoolID { +<# +.Synopsis + Recursive search for a Resource Pool within the results tree from ResourcePool_GetResourcePoolTree() and returns the ID + +.NOTES + ResourcePool_GetResourcePoolTree() returns ResourcePoolInfo as below + + ResourcePoolInfo.id Resource pool ID + ResourcePoolInfo.resourcePoolData + ResourcePoolInfo.resourcePoolData.name Resource pool name + ResourcePoolInfo.resourcePoolData.path Resource pool path + ResourcePoolInfo.resourcePoolData.type HOST_OR_CLUSTER, RESOURCE_POOL or OTHER + ResourcePoolInfo.children ResourcePoolInfo[] list of child nodes with potentially further child nodes + + Author : Mark Elvers +#> + param( + [Parameter(Mandatory = $true)] + [VMware.Hv.ResourcePoolInfo]$rpi + ) + if ($rpi.resourcePoolData.path -eq $resourcePool -or $rpi.resourcePoolData.name -eq $resourcePool) { + return $rpi.id + } + foreach ($child in $rpi.children) { + $id = Get-HVResourcePoolID $child + if ($id -ne $null) { + return $id + } + } + return $null +} + +function Get-HVAccessGroupID { +<# +.Synopsis + Recursive search for an Acess Group within the results tree from AccessGroup_List() and returns the ID + +.NOTES + AccessGroup_List() returns AccessGroupInfo[] (a list of structures) + + Iterate through the list of structures + AccessGroupInfo.id Access Group ID + AccessGroupInfo.base + AccessGroupInfo.base.name Access Group name + AccessGroupInfo.base.description Access Group description + AccessGroupInfo.base.parent Access Group parent ID + AccessGroupInfo.data + AccessGroupInfo.data.permissions PermissionID[] + AccessGroupInfo.children AccessGroupInfo[] list of child nodes with potentially further child nodes + + I couldn't create a child node of a child node via the Horizon View Administrator GUI, but the this code allows that if it occurs + Furthermore, unless you are using the Root access group you must iterate over the children + + Root -\ + +- Access Group 1 + +- Access Group 2 + \- Access Group 3 + + Author : Mark Elvers +#> + param( + [Parameter(Mandatory = $true)] + [VMware.Hv.AccessGroupInfo[]]$agi + ) + foreach ($element in $agi) { + if ($element.base.name -eq $accessGroup) { + return $element.id + } + foreach ($child in $element.children) { + $id = Get-HVAccessGroupID $child + if ($id -ne $null) { + return $id + } + } + } + return $null +} + function Get-HVPoolStorageObject { param( [Parameter(Mandatory = $true)] @@ -9599,4 +9714,3 @@ function Set-HVGlobalSettings { } Export-ModuleMember Add-HVDesktop,Add-HVRDSServer,Connect-HVEvent,Disconnect-HVEvent,Get-HVPoolSpec,Get-HVInternalName, Get-HVEvent,Get-HVFarm,Get-HVFarmSummary,Get-HVPool,Get-HVPoolSummary,Get-HVMachine,Get-HVMachineSummary,Get-HVQueryResult,Get-HVQueryFilter,New-HVFarm,New-HVPool,Remove-HVFarm,Remove-HVPool,Set-HVFarm,Set-HVPool,Start-HVFarm,Start-HVPool,New-HVEntitlement,Get-HVEntitlement,Remove-HVEntitlement, Set-HVMachine, New-HVGlobalEntitlement, Remove-HVGlobalEntitlement, Get-HVGlobalEntitlement, Get-HVPodSession, Set-HVApplicationIcon, Remove-HVApplicationIcon, Get-HVGlobalSettings, Set-HVGlobalSettings, Set-HVGlobalEntitlement - From dfd5a4e37edcf654dfde78c03a43defcef5edceb Mon Sep 17 00:00:00 2001 From: mtelvers Date: Wed, 25 Oct 2017 17:22:20 +0100 Subject: [PATCH 04/28] Fix for Find-HVMachine if no match is found in the first 1000 results If no match was found in the first 1000 results then the QueryService_GetNext() was never called as it used the length of the result array to detect the second pass through the loop --- Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 b/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 index dd7a66c..9c0cdb8 100644 --- a/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 +++ b/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 @@ -6910,19 +6910,22 @@ function Find-HVMachine { $query.Filter = $andFilter } $machineList = @() + $GetNext = $false $queryResults = $query_service_helper.QueryService_Create($services, $query) do { - if ($machineList.length -ne 0) { $queryResults = $query_service_helper.QueryService_GetNext($services, $queryResults.id) } + if ($GetNext) { $queryResults = $query_service_helper.QueryService_GetNext($services, $queryResults.id) } $machineList += $queryResults.results + $GetNext = $true } while ($queryResults.remainingCount -gt 0) $query_service_helper.QueryService_Delete($services, $queryResults.id) } if ($wildcard -or [string]::IsNullOrEmpty($machineList)) { $query.Filter = $null $machineList = @() + $GetNext = $false $queryResults = $query_service_helper.QueryService_Create($services,$query) do { - if ($machineList.length -ne 0) { $queryResults = $query_service_helper.QueryService_GetNext($services, $queryResults.id) } + if ($GetNext) { $queryResults = $query_service_helper.QueryService_GetNext($services, $queryResults.id) } $strFilterSet = @() foreach ($setting in $machineSelectors.Keys) { if ($null -ne $params[$setting]) { @@ -6936,6 +6939,7 @@ function Find-HVMachine { $whereClause = [string]::Join(' -and ', $strFilterSet) $scriptBlock = [Scriptblock]::Create($whereClause) $machineList += $queryResults.results | where $scriptBlock + $GetNext = $true } while ($queryResults.remainingCount -gt 0) $query_service_helper.QueryService_Delete($services, $queryResults.id) } From c2f137c812b70ad067afe277dc89ad93838269fd Mon Sep 17 00:00:00 2001 From: mtelvers Date: Fri, 27 Oct 2017 08:52:44 +0100 Subject: [PATCH 05/28] Updates to Set-HVPool Updated Set-HVPool to address issue #132. The -Start and -Stop parameter tested the wrong variable in the loop. $item is undefined. Furthermore, in general if the key/value pair specified $false as the value then the parameter wasn't seen in simple logic test such as if ($key -and $value) {}. I've updated to use $PSBoundParameters instead. --- Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 b/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 index 9c0cdb8..94f9939 100644 --- a/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 +++ b/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 @@ -5965,8 +5965,8 @@ function Set-HVPool { } if ($desktopPools) { foreach ($desktopObj in $desktopPools) { - if (($Start -or $Stop) -and ("AUTOMATED" -ne $item.DesktopSummaryData.Type)) { - Write-Error "Start/Stop operation is not supported for Poll with name : [$item.DesktopSummaryData.Name]" + if (($Start -or $Stop) -and ("AUTOMATED" -ne $desktopObj.DesktopSummaryData.Type)) { + Write-Error "Start/Stop operation is not supported for Pool with name : [$desktopObj.DesktopSummaryData.Name]" return } $poolList.add($desktopObj.id, $desktopObj.DesktopSummaryData.Name) @@ -5999,9 +5999,9 @@ function Set-HVPool { } } $updates = @() - if ($key -and $value) { + if ($PSBoundParameters.ContainsKey("key") -and $PSBoundParameters.ContainsKey("value")) { $updates += Get-MapEntry -key $key -value $value - } elseif ($key -or $value) { + } elseif ($PSBoundParameters.ContainsKey("key") -or $PSBoundParameters.ContainsKey("value")) { Write-Error "Both key:[$key] and value:[$value] needs to be specified" } if ($spec) { From 76820423a424f108dd5c3b79be5e4132c415677c Mon Sep 17 00:00:00 2001 From: Alan Comstock <31929022+Mr-Uptime@users.noreply.github.com> Date: Fri, 27 Oct 2017 09:16:39 -0500 Subject: [PATCH 06/28] Multipath to Round Robin on all FC disks in cluster This will configure multipath to round robin and IOPS to 1 on all disks in a cluster based upon the vendor type. This script is configured for 3par LUNs. Change $vendor for other storage types/vendors. --- Scripts/SetClusterMultiPathToRoundRobin.ps1 | 24 ++++++++------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/Scripts/SetClusterMultiPathToRoundRobin.ps1 b/Scripts/SetClusterMultiPathToRoundRobin.ps1 index 97bf311..396b038 100644 --- a/Scripts/SetClusterMultiPathToRoundRobin.ps1 +++ b/Scripts/SetClusterMultiPathToRoundRobin.ps1 @@ -2,28 +2,22 @@ Script name: SetClusterMultiPathToRoundRobin.ps1 Created on: 09/14/2017 Author: Alan Comstock, @Mr_Uptime - Description: Set the MultiPath policy for FC devices to RoundRobin for all hosts in a cluster. + Description: Set the MultiPath policy for FC devices to RoundRobin and IOPS to 1 for all hosts in a cluster based upon the vendor tag. Dependencies: None known PowerCLI Version: VMware PowerCLI 6.5 Release 1 build 4624819 PowerShell Version: 5.1.14393.1532 OS Version: Windows 10 #> -#Check for any Fibre Channel devices that are not set to Round Robin in a cluster. -#Get-Cluster -Name CLUSTERNAME | Get-VMhost | Get-VMHostHba -Type "FibreChannel" | Get-ScsiLun -LunType disk | Where { $_.MultipathPolicy -notlike "RoundRobin" } | Select CanonicalName,MultipathPolicy - -#Set the Multipathing Policy to Round Robin for any Fibre Channel devices that are not Round Robin in a cluster -$cluster = Get-Cluster CLUSTERNAME -$hostlist = Get-VMHost -Location $cluster | Sort Name -$TotalHostCount = $hostlist.count -$hostincrement = 0 -while ($hostincrement -lt $TotalHostCount){ #Host Loop - $currenthost = $hostlist[$hostincrement].Name - Write-Host "Working on" $currenthost - $scsilun = Get-VMhost $currenthost | Get-VMHostHba -Type "FibreChannel" | Get-ScsiLun -LunType disk | Where { $_.MultipathPolicy -notlike "RoundRobin" } +$pathpolicy="RoundRobin" +$iops="1" +$vendor="3PARdata" +$AllESXHosts = Get-VMHost -Location CLUSTERNAME | Sort Name +Foreach ($esxhost in $AllESXHosts) { + Write-Host "Working on" $esxhost + $scsilun = Get-VMhost $esxhost | Get-VMHostHba -Type "FibreChannel" | Get-ScsiLun -LunType disk | Where-Object {$_.Vendor -like $vendor -and ($_.MultipathPolicy -notlike $pathpolicy -or $_.CommandsToSwitchPath -ne $iops)} if ($scsilun -ne $null){ - Set-ScsiLun -ScsiLun $scsilun -MultipathPolicy RoundRobin + Set-ScsiLun -ScsiLun $scsilun -MultipathPolicy $pathpolicy -CommandsToSwitchPath $iops } - $hostincrement++ #bump the host increment } #The End From dc523953cacedeeb0d00e22e6ea38b8ea9682111 Mon Sep 17 00:00:00 2001 From: Alan Comstock <31929022+Mr-Uptime@users.noreply.github.com> Date: Fri, 27 Oct 2017 09:25:47 -0500 Subject: [PATCH 07/28] Adds VLANs to an existing standard switch This script will add VLANs to an existing standard switch on a host. Information needed: $esxhost - Name of host $vswitch - Name of existing standard switch $vlanlist - List of all the VLANs you want to add to the switch --- Scripts/CreateVLANonStandardSwitch | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Scripts/CreateVLANonStandardSwitch diff --git a/Scripts/CreateVLANonStandardSwitch b/Scripts/CreateVLANonStandardSwitch new file mode 100644 index 0000000..d64b221 --- /dev/null +++ b/Scripts/CreateVLANonStandardSwitch @@ -0,0 +1,19 @@ +<# + Script name: CreateVLANonStandardSwitch.ps1 + Created on: 10/26/2017 + Author: Alan Comstock, @Mr_Uptime + Description: Adds VLANs to an existing standard switch + Dependencies: None known + PowerCLI Version: VMware PowerCLI 6.5 Release 1 build 4624819 + PowerShell Version: 5.1.14393.1532 + OS Version: Windows 10 +#> + +$esxhost="HOSTNAME" +$vswitch="vSwitch0" +$vlanlist=10,20,30,40,50 +Foreach ($vlan in $vlanlist) { + $portgroupname="VLAN " + $vlan + Get-VMHost $esxhost | Get-VirtualSwitch -name $vswitch | New-VirtualPortGroup -Name $portgroupname -VLanId $vlan +} +#The End From 77adef309d9774ebc3a558895c99650feffb9a76 Mon Sep 17 00:00:00 2001 From: William Lam Date: Sun, 29 Oct 2017 13:45:29 -0700 Subject: [PATCH 08/28] Adding NSXT Module --- Modules/NSXT/NSXT.psd1 | 18 +++ Modules/NSXT/NSXT.psm1 | 260 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 278 insertions(+) create mode 100644 Modules/NSXT/NSXT.psd1 create mode 100644 Modules/NSXT/NSXT.psm1 diff --git a/Modules/NSXT/NSXT.psd1 b/Modules/NSXT/NSXT.psd1 new file mode 100644 index 0000000..c3371b3 --- /dev/null +++ b/Modules/NSXT/NSXT.psd1 @@ -0,0 +1,18 @@ +@{ + ModuleToProcess = 'NSXT.psm1' + ModuleVersion = '1.0.0.0' + GUID = 'c72f4e3d-5d1d-498f-ba86-6fa03e4ae6dd' + Author = 'William Lam' + CompanyName = 'primp-industries.com' + Copyright = '(c) 2017. All rights reserved.' + Description = 'Powershell Module for NSX-T REST API Functions' + PowerShellVersion = '5.0' + FunctionsToExport = 'Get-NSXTComputeManager','Get-NSXTFabricNode','Get-NSXTFirewallRule','Get-NSXTIPPool','Get-NSXTLogicalSwitch','Get-NSXTManager','Get-NSXTTransportZone','Get-NSXTController' + PrivateData = @{ + PSData = @{ + Tags = @('NSX-T','REST') + LicenseUri = 'https://www.tldrlegal.com/l/mit' + ProjectUri = 'https://github.com/lamw/PowerCLI-Example-Scripts/tree/master/Modules/NSXT' + } + } +} \ No newline at end of file diff --git a/Modules/NSXT/NSXT.psm1 b/Modules/NSXT/NSXT.psm1 new file mode 100644 index 0000000..f8dcb49 --- /dev/null +++ b/Modules/NSXT/NSXT.psm1 @@ -0,0 +1,260 @@ +Function Get-NSXTController { + Param ( + [parameter(Mandatory=$false,ValueFromPipeline=$true)][string]$Id + ) + + $clusterNodeService = Get-NsxtService -Name "com.vmware.nsx.cluster.nodes" + $clusterNodeStatusService = Get-NsxtService -Name "com.vmware.nsx.cluster.nodes.status" + if($Id) { + $nodes = $clusterNodeService.get($Id) + } else { + $nodes = $clusterNodeService.list().results | where { $_.manager_role -eq $null } + } + + $results = @() + foreach ($node in $nodes) { + $nodeId = $node.id + $nodeName = $node.controller_role.control_plane_listen_addr.ip_address + $nodeStatusResults = $clusterNodeStatusService.get($nodeId) + + $tmp = [pscustomobject] @{ + Id = $nodeId; + Name = $nodeName; + ClusterStatus = $nodeStatusResults.control_cluster_status.control_cluster_status; + Version = $nodeStatusResults.version; + + } + $results+=$tmp + } + $results +} + +Function Get-NSXTFabricNode { + Param ( + [parameter(Mandatory=$false,ValueFromPipeline=$true)][string]$Id, + [Switch]$ESXi, + [Switch]$Edge + ) + + $fabricNodeService = Get-NsxtService -Name "com.vmware.nsx.fabric.nodes" + $fabricNodeStatusService = Get-NsxtService -Name "com.vmware.nsx.fabric.nodes.status" + if($Id) { + $nodes = $fabricNodeService.get($Id) + } else { + if($ESXi) { + $nodes = $fabricNodeService.list().results | where { $_.resource_type -eq "HostNode" } + } elseif ($Edge) { + $nodes = $fabricNodeService.list().results | where { $_.resource_type -eq "EdgeNode" } + } else { + $nodes = $fabricNodeService.list().results + } + } + + $results = @() + foreach ($node in $nodes) { + $nodeStatusResult = $fabricNodeStatusService.get($node.id) + + $tmp = [pscustomobject] @{ + Id = $node.id; + Name = $node.display_name; + Type = $node.resource_type; + Address = $node.ip_addresses; + NSXVersion = $nodeStatusResult.software_version + OS = $node.os_type; + Version = $node.os_version; + Status = $nodeStatusResult.host_node_deployment_status + ManagerStatus = $nodeStatusResult.mpa_connectivity_status + ControllerStatus = $nodeStatusResult.lcp_connectivity_status + } + $results+=$tmp + } + $results +} + +Function Get-NSXTIPPool { + Param ( + [parameter(Mandatory=$false,ValueFromPipeline=$true)][string]$Id + ) + + $ipPoolService = Get-NsxtService -Name "com.vmware.nsx.pools.ip_pools" + + if($Id) { + $ipPools = $ipPoolService.get($Id) + } else { + $ipPools = $ipPoolService.list().results + } + + $results = @() + foreach ($ipPool in $ipPools) { + $tmp = [pscustomobject] @{ + Id = $ipPool.Id; + Name = $ipPool.Display_Name; + Total = $ipPool.pool_usage.total_ids; + Free = $ipPool.pool_usage.free_ids; + Network = $ipPool.subnets.cidr; + Gateway = $ipPool.subnets.gateway_ip; + DNS = $ipPool.subnets.dns_nameservers; + RangeStart = $ipPool.subnets.allocation_ranges.start; + RangeEnd = $ipPool.subnets.allocation_ranges.end + } + $results+=$tmp + } + $results +} + +Function Get-NSXTTransportZone { + Param ( + [parameter(Mandatory=$false,ValueFromPipeline=$true)][string]$Id + ) + + $transportZoneService = Get-NsxtService -Name "com.vmware.nsx.transport_zones" + + if($Id) { + $transportZones = $transportZoneService.get($Id) + } else { + $transportZones = $transportZoneService.list().results + } + + $results = @() + foreach ($transportZone in $transportZones) { + $tmp = [pscustomobject] @{ + Id = $transportZone.Id; + Name = $transportZone.display_name; + Type = $transportZone.transport_type; + HostSwitchName = $transportZone.host_switch_name; + } + $results+=$tmp + } + $results +} + +Function Get-NSXTComputeManager { + Param ( + [parameter(Mandatory=$false,ValueFromPipeline=$true)][string]$Id + ) + + $computeManagerSerivce = Get-NsxtService -Name "com.vmware.nsx.fabric.compute_managers" + $computeManagerStatusService = Get-NsxtService -Name "com.vmware.nsx.fabric.compute_managers.status" + + if($Id) { + $computeManagers = $computeManagerSerivce.get($id) + } else { + $computeManagers = $computeManagerSerivce.list().results + } + + $results = @() + foreach ($computeManager in $computeManagers) { + $computeManagerStatus = $computeManagerStatusService.get($computeManager.Id) + + $tmp = [pscustomobject] @{ + Id = $computeManager.Id; + Name = $computeManager.display_name; + Server = $computeManager.server + Type = $computeManager.origin_type; + Version = $computeManagerStatus.Version; + Registration = $computeManagerStatus.registration_status; + Connection = $computeManagerStatus.connection_status; + } + $results+=$tmp + } + $results +} + +Function Get-NSXTLogicalSwitch { + Param ( + [parameter(Mandatory=$false,ValueFromPipeline=$true)][string]$Id + ) + + $logicalSwitchService = Get-NsxtService -Name "com.vmware.nsx.logical_switches" + $logicalSwitchSummaryService = Get-NsxtService -Name "com.vmware.nsx.logical_switches.summary" + + if($Id) { + $logicalSwitches = $logicalSwitchService.get($Id) + } else { + $logicalSwitches = $logicalSwitchService.list().results + } + + $results = @() + foreach ($logicalSwitch in $logicalSwitches) { + $transportZone = (Get-NSXTTransportZone -Id $logicalSwitch.transport_zone_id | Select Name | ft -HideTableHeaders | Out-String).trim() + $ports = $logicalSwitchSummaryService.get($logicalSwitch.id).num_logical_ports + + $tmp = [pscustomobject] @{ + Id = $logicalSwitch.Id; + Name = $logicalSwitch.display_name; + VLAN = $logicalSwitch.vlan; + AdminStatus = $logicalSwitch.admin_state; + Ports = $ports; + TransportZone = $transportZone; + } + $results+=$tmp + } + $results +} + +Function Get-NSXTFirewallRule { + Param ( + [parameter(Mandatory=$false,ValueFromPipeline=$true)][string]$Id + ) + + $firewallService = Get-NsxtService -Name "com.vmware.nsx.firewall.sections" + $firewallRuleService = Get-NsxtService -Name "com.vmware.nsx.firewall.sections.rules" + + if($Id) { + $firewallRuleSections = $firewallService.get($Id) + } else { + $firewallRuleSections = $firewallService.list().results + } + + $sectionResults = @() + foreach ($firewallRuleSection in $firewallRuleSections) { + $tmp = [pscustomobject] @{ + Id = $firewallRuleSection.Id; + Name = $firewallRuleSection.display_name; + Type = $firewallRuleSection.section_type; + Stateful = $firewallRuleSection.stateful; + RuleCount = $firewallRuleSection.rule_count; + } + $sectionResults+=$tmp + } + $sectionResults + + $firewallResults = @() + if($id) { + $firewallRules = $firewallRuleService.list($id).results + foreach ($firewallRule in $firewallRules) { + $tmp = [pscustomobject] @{ + Id = $firewallRule.id; + Name = $firewallRule.display_name; + Sources = if($firewallRule.sources -eq $null) { "ANY" } else { $firewallRule.sources}; + Destination = if($firewallRule.destinations -eq $null) { "ANY" } else { $firewallRule.destinations }; + Services = if($firewallRule.services -eq $null) { "ANY" } else { $firewallRule.services } ; + Action = $firewallRule.action; + AppliedTo = if($firewallRule.applied_tos -eq $null) { "ANY" } else { $firewallRule.applied_tos }; + Log = $firewallRule.logged; + } + $firewallResults+=$tmp + } + } + $firewallResults +} + +Function Get-NSXTManager { + $clusterNodeService = Get-NsxtService -Name "com.vmware.nsx.cluster.nodes" + + $nodes = $clusterNodeService.list().results + + $results = @() + foreach ($node in $nodes) { + if($node.manager_role -ne $null) { + $tmp = [pscustomobject] @{ + Id = $node.id; + Name = $node.display_name; + Address = $node.appliance_mgmt_listen_addr; + SHA256Thumbprint = $node.manager_role.api_listen_addr.certificate_sha256_thumbprint; + } + $results+=$tmp + } + } + $results +} \ No newline at end of file From df32c591484a3e90ef78086b19a73f9703253764 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 31 Oct 2017 11:17:36 -0400 Subject: [PATCH 09/28] Use the item in foreach rather than collection Error message should use $v rather than $vm --- Scripts/Get-VMNetworkPortId.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/Get-VMNetworkPortId.ps1 b/Scripts/Get-VMNetworkPortId.ps1 index ed130a6..eeb2e62 100644 --- a/Scripts/Get-VMNetworkPortId.ps1 +++ b/Scripts/Get-VMNetworkPortId.ps1 @@ -30,7 +30,7 @@ foreach ($v in $vm) { #Validate the input is a valid VM $vmobj = Get-VM -Name $v -erroraction silentlycontinue - if (!$vmobj) {Write-Verbose "No VM found by the name $vm."} + if (!$vmobj) {Write-Verbose "No VM found by the name $v."} else { #Create a temporary object to store individual ouput $tempout = "" | select VM,PortId From 5879c10003763c57ba61cc8530571555cf024977 Mon Sep 17 00:00:00 2001 From: mtelvers Date: Thu, 2 Nov 2017 22:18:41 +0000 Subject: [PATCH 10/28] Fixes to Get-HVDatastore() when multiple datastores are specified `$Datastores` needs to be initialized as an empty array `@()` rather than `$null`. Furthermore, if `$DsStroageOvercommit` is empty it is only initialised with a single element where there should be one element per datastore. I've moved the test into the loop instead. --- Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 b/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 index 94f9939..127c056 100644 --- a/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 +++ b/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 @@ -5039,15 +5039,16 @@ function Get-HVDatastore { foreach ($ds in $datastoreNames) { $datastoresSelected += ($datastoreInfoList | Where-Object { ($_.DatastoreData.Path -eq $ds) -or ($_.datastoredata.name -eq $ds) }).id } - $Datastores = $null - if (! $DsStorageOvercommit) { - $DsStorageOvercommit += 'UNBOUNDED' - } + $Datastores = @() $StorageOvercommitCnt = 0 foreach ($ds in $datastoresSelected) { $myDatastores = New-Object VMware.Hv.DesktopVirtualCenterDatastoreSettings $myDatastores.Datastore = $ds - $mydatastores.StorageOvercommit = $DsStorageOvercommit[$StorageOvercommitCnt] + if (! $DsStorageOvercommit) { + $mydatastores.StorageOvercommit = 'UNBOUNDED' + } else { + $mydatastores.StorageOvercommit = $DsStorageOvercommit[$StorageOvercommitCnt] + } $Datastores += $myDatastores $StorageOvercommitCnt++ } From d406e54b19381dd6e7d6e6727fd9a0079fa97a67 Mon Sep 17 00:00:00 2001 From: mtelvers Date: Fri, 3 Nov 2017 11:17:27 +0000 Subject: [PATCH 11/28] Fix to New-HVPool when persistent datastores are specified Function Get_Datastore should read Get-HVDatastore --- Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 b/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 index 127c056..e05be97 100644 --- a/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 +++ b/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 @@ -3239,6 +3239,10 @@ function New-HVPool { Datastore names to store the VM Applicable to Full, Linked, Instant Clone Pools. +.PARAMETER StorageOvercommit + Storage overcommit determines how View places new VMs on the selected datastores. + Supported values are 'UNBOUNDED','AGGRESSIVE','MODERATE','CONSERVATIVE','NONE' and are case sensitive. + .PARAMETER UseVSAN Whether to use vSphere VSAN. This is applicable for vSphere 5.5 or later. Applicable to Full, Linked, Instant Clone Pools. @@ -3269,6 +3273,7 @@ function New-HVPool { .PARAMETER PersistentDiskStorageOvercommit Storage overcommit determines how view places new VMs on the selected datastores. + Supported values are 'UNBOUNDED','AGGRESSIVE','MODERATE','CONSERVATIVE','NONE' and are case sensitive. .PARAMETER DiskSizeMB Size of the persistent disk in MB. @@ -4986,7 +4991,7 @@ function Get-HVPoolStorageObject { if ($persistentDiskStorageOvercommit -and ($persistentDiskDatastores.Length -ne $persistentDiskStorageOvercommit.Length) ) { throw "Parameters persistentDiskDatastores length: [$persistentDiskDatastores.Length] and persistentDiskStorageOvercommit length: [$persistentDiskStorageOvercommit.Length] should be of same size" } - $desktopPersistentDiskSettings.PersistentDiskDatastores = Get_Datastore -DatastoreInfoList $datastoreList -DatastoreNames $PersistentDiskDatastores -DsStorageOvercommit $persistentDiskStorageOvercommit + $desktopPersistentDiskSettings.PersistentDiskDatastores = Get-HVDatastore -DatastoreInfoList $datastoreList -DatastoreNames $PersistentDiskDatastores -DsStorageOvercommit $persistentDiskStorageOvercommit } $desktopNonPersistentDiskSettings.RedirectDisposableFiles = $redirectDisposableFiles $desktopNonPersistentDiskSettings.DiskSizeMB = $nonPersistentDiskSizeMB From 9e588e39c9515e12595431659d60802d929ed4e2 Mon Sep 17 00:00:00 2001 From: mtelvers Date: Fri, 3 Nov 2017 17:13:44 +0000 Subject: [PATCH 12/28] Added -ResourcePool to Set-HVPool Update Set-HVPool to allow you to set a new resource pool within the same host/cluster --- .../.VMware.HV.Helper.psm1.swp | Bin 0 -> 458752 bytes Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 | 13 +++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 Modules/VMware.Hv.Helper/.VMware.HV.Helper.psm1.swp diff --git a/Modules/VMware.Hv.Helper/.VMware.HV.Helper.psm1.swp b/Modules/VMware.Hv.Helper/.VMware.HV.Helper.psm1.swp new file mode 100644 index 0000000000000000000000000000000000000000..803f4193b5e2339e38b9b7e6408b61ce5a3d27d1 GIT binary patch literal 458752 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 z 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 A_W%F@ literal 0 HcmV?d00001 diff --git a/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 b/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 index e05be97..9d07050 100644 --- a/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 +++ b/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 @@ -5941,6 +5941,10 @@ function Set-HVPool { [string] $globalEntitlement, + [Parameter(Mandatory = $false)] + [string] + $ResourcePool, + [Parameter(Mandatory = $false)] [boolean]$allowUsersToChooseProtocol, @@ -6044,6 +6048,15 @@ function Set-HVPool { $updates += Get-MapEntry -key 'desktopSettings.displayProtocolSettings.enableHTMLAccess' -value $enableHTMLAccess } + if ($PSBoundParameters.ContainsKey("ResourcePool")) { + foreach ($item in $poolList.Keys) { + $pool = Get-HVPool -PoolName $poolList.$item + $ResourcePool_service_helper = New-Object VMware.Hv.ResourcePoolService + $ResourcePoolID = Get-HVResourcePoolID $ResourcePool_service_helper.ResourcePool_GetResourcePoolTree($services, $pool.AutomatedDesktopData.VirtualCenterProvisioningSettings.VirtualCenterProvisioningData.HostOrCluster) + $updates += Get-MapEntry -key 'automatedDesktopData.virtualCenterProvisioningSettings.virtualCenterProvisioningData.resourcePool' -value $ResourcePoolID + } + } + $info = $services.PodFederation.PodFederation_get() if ($globalEntitlement -and ("ENABLED" -eq $info.localPodStatus.status)) { $QueryFilterEquals = New-Object VMware.Hv.QueryFilterEquals From 6b4bbf562d5effaaa08eebd512891fb325836aa4 Mon Sep 17 00:00:00 2001 From: mtelvers Date: Fri, 3 Nov 2017 17:18:55 +0000 Subject: [PATCH 13/28] Delete .VMware.HV.Helper.psm1.swp --- .../.VMware.HV.Helper.psm1.swp | Bin 458752 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Modules/VMware.Hv.Helper/.VMware.HV.Helper.psm1.swp diff --git a/Modules/VMware.Hv.Helper/.VMware.HV.Helper.psm1.swp b/Modules/VMware.Hv.Helper/.VMware.HV.Helper.psm1.swp deleted file mode 100644 index 803f4193b5e2339e38b9b7e6408b61ce5a3d27d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 458752 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 z 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 A_W%F@ From 77d44734d46f9029f2ed35a9606b86fd9a92f670 Mon Sep 17 00:00:00 2001 From: mtelvers Date: Mon, 6 Nov 2017 11:15:26 +0000 Subject: [PATCH 14/28] Add Get-HVResourceStructure to display the Resouce Pool structure Display the resource pools available to the Horizon View server --- .../VMware.Hv.Helper/VMware.HV.Helper.psm1 | 88 ++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 b/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 index 9d07050..d90aaf1 100644 --- a/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 +++ b/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1 @@ -4740,6 +4740,92 @@ function New-HVPool { } } +function Get-HVResourceStructure { +<# +.Synopsis + Output the structure of the resource pools available to a HV. Primarily this is for debugging + + PS> Get-HVResourceStructure + vCenter vc.domain.local + Container DC path /DC/host + HostOrCluster Servers path /DC/host/Servers + HostOrCluster VDI path /DC/host/VDI + ResourcePool Servers path /DC/host/Servers/Resources + ResourcePool VDI path /DC/host/VDI/Resources + ResourcePool RP1 path /DC/host/VDI/Resources/RP1 + ResourcePool RP2 path /DC/host/VDI/Resources/RP1/RP2 + + Author : Mark Elvers +#> + param( + [Parameter(Mandatory = $false)] + $HvServer = $null + ) + begin { + $services = Get-ViewAPIService -hvServer $HvServer + if ($null -eq $services) { + Write-Error "Could not retrieve ViewApi services from connection object" + break + } + } + process { + $vc_service_helper = New-Object VMware.Hv.VirtualCenterService + $vcList = $vc_service_helper.VirtualCenter_List($services) + foreach ($vc in $vcList) { + Write-Host vCenter $vc.ServerSpec.ServerName + $datacenterList = @{} + $BaseImage_service_helper = New-Object VMware.Hv.BaseImageVmService + $parentList = $BaseImage_service_helper.BaseImageVm_List($services, $vc.id) + foreach ($possibleParent in $parentList) { + if (-not $datacenterList.ContainsKey($possibleParent.datacenter.id)) { + $datacenterList.Add($possibleParent.datacenter.id, $possibleParent.datacenter) + } + if (0) { + Write-Host "$($possibleParent.name): " -NoNewLine + if ($possibleParent.incompatibleReasons.inUseByDesktop) { Write-Host "inUseByDesktop, " -NoNewLine } + if ($possibleParent.incompatibleReasons.viewComposerReplica) { Write-Host "viewComposerReplica, " -NoNewLine } + if ($possibleParent.incompatibleReasons.inUseByLinkedCloneDesktop) { Write-Host "inUseByLinkedCloneDesktop, " -NoNewLine } + if ($possibleParent.incompatibleReasons.unsupportedOSForLinkedCloneFarm) { Write-Host "unsupportedOSForLinkedCloneFarm, " -NoNewLine } + if ($possibleParent.incompatibleReasons.unsupportedOS) { Write-Host "unsupportedOS, " -NoNewLine } + if ($possibleParent.incompatibleReasons.noSnapshots) { Write-Host "noSnapshots, " -NoNewLine } + Write-Host + } + } + $hcNodes = @() + $index = 0 + foreach ($datacenter in $datacenterList.keys) { + $HostOrCluster_service_helper = New-Object VMware.Hv.HostOrClusterService + $hcNodes += $HostOrCluster_service_helper.HostOrCluster_GetHostOrClusterTree($services, $datacenterList.$datacenter) + while ($index -lt $hcNodes.length) { + if ($hcNodes[$index].container) { + Write-Host "Container" $hcNodes[$index].treecontainer.name "path" $hcNodes[$index].treecontainer.path + if ($hcNodes[$index].treecontainer.children.Length) { $hcNodes += $hcNodes[$index].treecontainer.children } + } else { + Write-Host "HostOrCluster" $hcNodes[$index].info.name "path" $hcNodes[$index].info.path + } + $index++ + } + } + $rpNodes = @() + $index = 0 + foreach ($hostOrCluster in $hcNodes) { + if (-not $hostOrCluster.container) { + $ResourcePool_service_helper = New-Object VMware.Hv.ResourcePoolService + $rpNodes += $ResourcePool_service_helper.ResourcePool_GetResourcePoolTree($services, $hostOrCluster.info.id) + while ($index -lt $rpNodes.length) { + Write-Host "ResourcePool" $rpNodes[$index].resourcePoolData.name "path" $rpNodes[$index].resourcePoolData.path + if ($rpNodes[$index].children.Length) { $rpNodes += $rpNodes[$index].children } + $index++ + } + } + } + } + } + end { + [System.gc]::collect() + } +} + function Get-HVPoolProvisioningData { param( [Parameter(Mandatory = $false)] @@ -9736,4 +9822,4 @@ function Set-HVGlobalSettings { } } -Export-ModuleMember Add-HVDesktop,Add-HVRDSServer,Connect-HVEvent,Disconnect-HVEvent,Get-HVPoolSpec,Get-HVInternalName, Get-HVEvent,Get-HVFarm,Get-HVFarmSummary,Get-HVPool,Get-HVPoolSummary,Get-HVMachine,Get-HVMachineSummary,Get-HVQueryResult,Get-HVQueryFilter,New-HVFarm,New-HVPool,Remove-HVFarm,Remove-HVPool,Set-HVFarm,Set-HVPool,Start-HVFarm,Start-HVPool,New-HVEntitlement,Get-HVEntitlement,Remove-HVEntitlement, Set-HVMachine, New-HVGlobalEntitlement, Remove-HVGlobalEntitlement, Get-HVGlobalEntitlement, Get-HVPodSession, Set-HVApplicationIcon, Remove-HVApplicationIcon, Get-HVGlobalSettings, Set-HVGlobalSettings, Set-HVGlobalEntitlement +Export-ModuleMember Add-HVDesktop,Add-HVRDSServer,Connect-HVEvent,Disconnect-HVEvent,Get-HVPoolSpec,Get-HVInternalName, Get-HVEvent,Get-HVFarm,Get-HVFarmSummary,Get-HVPool,Get-HVPoolSummary,Get-HVMachine,Get-HVMachineSummary,Get-HVQueryResult,Get-HVQueryFilter,New-HVFarm,New-HVPool,Remove-HVFarm,Remove-HVPool,Set-HVFarm,Set-HVPool,Start-HVFarm,Start-HVPool,New-HVEntitlement,Get-HVEntitlement,Remove-HVEntitlement, Set-HVMachine, New-HVGlobalEntitlement, Remove-HVGlobalEntitlement, Get-HVGlobalEntitlement, Get-HVPodSession, Set-HVApplicationIcon, Remove-HVApplicationIcon, Get-HVGlobalSettings, Set-HVGlobalSettings, Set-HVGlobalEntitlement, Get-HVResourceStructure From 14256a32a87ee2bb607feba0bed4e3d6da3f6d77 Mon Sep 17 00:00:00 2001 From: daoyuanw Date: Tue, 14 Nov 2017 14:43:47 +0800 Subject: [PATCH 15/28] Add VMToolsManagment for VMTools upgrade, guest info query .etc --- .../VMToolsManagement/VMToolsManagement.psm1 | 1149 +++++++++++++++++ 1 file changed, 1149 insertions(+) create mode 100644 Modules/VMToolsManagement/VMToolsManagement.psm1 diff --git a/Modules/VMToolsManagement/VMToolsManagement.psm1 b/Modules/VMToolsManagement/VMToolsManagement.psm1 new file mode 100644 index 0000000..bbfdf5e --- /dev/null +++ b/Modules/VMToolsManagement/VMToolsManagement.psm1 @@ -0,0 +1,1149 @@ +# Script Module : VMToolsManagement +# Version : 1.0 + +# Copyright © 2017 VMware, Inc. All Rights Reserved. + +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +New-VIProperty -Name ToolsBuildNumber -Object VirtualMachine -Value { + Param ($VM) + + foreach ($item in $VM.ExtensionData.Config.ExtraConfig.GetEnumerator()) { + if ($item.Key -eq "guestinfo.vmtools.buildNumber") { + $toolsBuildNumber = $item.value + break + } + } + + return $toolsBuildNumber +} -BasedOnExtensionProperty 'Config.ExtraConfig' -Force | Out-Null + +Function Get-VMToolsInfo { +<# +.SYNOPSIS + This cmdlet retrieves the VMTools info of specified virtual machines. + +.DESCRIPTION + This cmdlet retrieves the VMTools version and build number info of specified virtual machines. + +.PARAMETER VM + Specifies the virtual machines which you want to get the VMTools info of. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password + C:\PS> Get-VM -Server $VCServer | Get-VMToolsInfo + + Retrieves VMTools info of all virtual machines which run in the $VCServer vCetner Server. + +.EXAMPLE + C:\PS> Get-VM "*rhel*" | Get-VMToolsInfo + + Name ToolsVersion ToolsBuildNumber + ------ ------------ ---------------- + 111394-RHEL-6.8-0 10.2.0 6090153 + 111394-RHEL-6.8-1 9.0.15 + 111393-RHEL-Server-7.2 10.1.0 + + Retrieves VMTools info of virtual machines with name containing "rhel". + +.EXAMPLE + C:\PS> Get-VM -Location "MyClusterName" | Get-VMToolsInfo + + Retrieves VMTools info from virtual machines which run in the "MyClusterName" cluster. + +.EXAMPLE + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Get-VMToolsInfo + + Retrieves VMTools info of virtual machines which run on the "MyESXiHostName" ESXi host. + +.NOTES + This cmdlet assumes that you are connected to at least one vCenter Server system. + The tools build number is not supported in VMTools before 10.2.0 + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM + ) + + Process { + Get-VM $VM | Select Name, @{Name="ToolsVersion"; Expression={$_.Guest.ToolsVersion}}, ToolsBuildNumber + } +} + +Function Get-VMToolsInstallLastError { +<# +.SYNOPSIS + This cmdlet retrieves the error code of last VMTools installation. + +.DESCRIPTION + This cmdlet retrieves the error code of last VMTools installation on specified virtual machines. + +.PARAMETER VM + Specifies the virtual machines which you want to get the error code of. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password + C:\PS> Get-VM -Server $VCServer | Get-VMToolsInstallLastError + + Retrieves the last VMTools installation error code of all virtual machines which run in the $VCServer vCetner Server. + +.EXAMPLE + C:\PS> Get-VM "*win*" | Get-VMToolsInstallLastError + + Name LastToolsInstallErrCode + ------ ----------------------- + 111167-Win-7-Sp1-64-Enterprise-NoTools + 111323-Windows-8.1U3-32-Enterprise-Tools + 111305-Windows-Server2016 1641 + + Retrieves the last VMTools installation error code of virtual machines with name containing "win". + +.EXAMPLE + C:\PS> Get-VM -Location "MyClusterName" | Get-VMToolsInstallLastError + + Retrieves the last VMTools installation error code of virtual machines which run in the "MyClusterName" cluster. + +.EXAMPLE + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Get-VMToolsInstallLastError + + Retrieves the last VMTools installation error code of virtual machines which run on the "MyESXiHostName" ESXi host. + +.NOTES + This cmdlet assumes that you are connected to at least one vCenter Server system. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819)(build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM + ) + + Process { + $result = @() + foreach ($_ in $VM) { + $errorCodeInfo = $_.ExtensionData.Config.ExtraConfig.GetEnumerator() | where {$_.Key -eq "guestinfo.toolsInstallErrCode"} + + $info = New-Object PSObject + $info | Add-Member -type NoteProperty -name VmName -value $_.Name + $info | Add-Member -type NoteProperty -name LastToolsInstallErrCode -value $errorCodeInfo.Value + + $result += $info + } + $result + } +} + +Function Get-VMToolsGuestInfo { +<# +.SYNOPSIS + This cmdlet retrieves the guest info of specified virtual machines. + +.DESCRIPTION + This cmdlet retrieves the guest info such as HostName, IP, ToolsStatus, ToolsVersion, + ToolsInstallType and GuestFamily of specified virtual machines. + +.PARAMETER VM + Specifies the virtual machines which you want to get the guest info of. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password + C:\PS> Get-VM -Server $VCServer | Get-VMToolsGuestInfo + + Retrieves guest info of all virtual machines which run in the $VCServer vCetner Server. + +.EXAMPLE + C:\PS> Get-VM "*win*" | Get-VMToolsGuestInfo + + Name : 111323-Windows-8.1U3-32-Enterprise-Tools + HostName : win81u3 + IP : + ToolsStatus : toolsNotRunning + ToolsVersion : 10.2.0 + ToolsInstallType : guestToolsTypeMSI + GuestFamily : windowsGuest + VMPowerState : PoweredOff + + Name : 111305-Windows-Server2016 + HostName : WIN-ULETOOSSB7U + IP : 10.160.59.99 + ToolsStatus : toolsOk + ToolsVersion : 10.1.0 + ToolsInstallType : guestToolsTypeMSI + GuestFamily : windowsGuest + VMPowerState : PoweredOn + + Retrieves guest info of virtual machines with name containing "win". + +.EXAMPLE + C:\PS> Get-VM -Location "MyClusterName" | Get-VMToolsGuestInfo + + Retrieves guest info of virtual machines which run in the "MyClusterName" cluster. + +.EXAMPLE + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Get-VMToolsGuestInfo + + Retrieves guest info of virtual machines which run on the "MyESXiHostName" ESXi host. + +.NOTES + This cmdlet assumes that you are connected to at least one vCenter Server system. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819)(build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM + ) + + Process { + Get-VM $VM | Select Name, @{Name="HostName"; Expression={$_.Guest.HostName}}, + @{Name="IP"; Expression={$_.Guest.ExtensionData.IpAddress}}, + @{Name="ToolsStatus"; Expression={$_.Guest.ExtensionData.ToolsStatus}}, + @{Name="ToolsVersion"; Expression={$_.Guest.ToolsVersion}}, + @{Name="ToolsInstallType"; Expression={$_.Guest.ExtensionData.ToolsInstallType}}, + @{Name="GuestFamily"; Expression={$_.Guest.GuestFamily}}, + PowerState + } +} + +Function Get-VMByToolsInfo { +<# +.SYNOPSIS + This cmdlet retrieves the virtual machines with specified VMTools info. + +.DESCRIPTION + This cmdlet retrieves the virtual machines with specified VMTools version, + running status or version status. + +.PARAMETER VM + Specifies the virtual machines which you want to query VMTools status of. + +.PARAMETER ToolsVersion + Specifies the VMTools version. + +.PARAMETER ToolsRunningStatus + Specifies the VMTools running status. + +.PARAMETER ToolsVersionStatus + Specifies the VMTools version status. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password + C:\PS> Get-VM -Server $VCServer | Get-VMByToolsInfo + + Retrieves the virtual machines with VMTools not running in vCetner Server $VCServer. + +.EXAMPLE + C:\PS> Get-VM | Get-VMByToolsInfo -ToolsRunningStatus guestToolsNotRunning + + Name PowerState Num CPUs MemoryGB + ---- ---------- -------- -------- + 111394-RHEL-6.8-1 PoweredOff 4 2.000 + + Retrieves all the virtual machines with VMTools not running. + +.EXAMPLE + C:\PS> Get-VM | Get-VMByToolsInfo -ToolsVersion '10.1.0' + + Name PowerState Num CPUs MemoryGB + ---- ---------- -------- -------- + 111394-RHEL-6.8-1 PoweredOff 4 2.000 + + Retrieves the virtual machines with VMTools version 10.1.0. + +.EXAMPLE + C:\PS> Get-VM -Location "MyClusterName" | Get-VMByToolsInfo -ToolsVersionStatus guestToolsNeedUpgrade + + Retrieves the virtual machines with VMTools that need to upgrade in the "MyClusterName" cluster. + +.EXAMPLE + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Get-VMByToolsInfo -ToolsRunningStatus guestToolsRunning -ToolsVersionStatus guestToolsNeedUpgrade + + Retrieves the virtual machines with VMTools that need to upgrade on the "MyESXiHostName" ESXi host. + +.NOTES + This cmdlet assumes that you are connected to at least one vCenter Server system. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587)(build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM, + + [Parameter(Mandatory=$false)] + [String] $ToolsVersion, + + [Parameter(Mandatory=$false)] + [ValidateSet("guestToolsRunning", + "guestToolsNotRunning", + "guestToolsExecutingScripts")] + [String] $ToolsRunningStatus, + + [Parameter(Mandatory=$false)] + [ValidateSet("guestToolsNotInstalled", + "guestToolsNeedUpgrade", + "guestToolsCurrent", + "guestToolsUnmanaged")] + [String] $ToolsVersionStatus + ) + + Process { + $vmList = Get-VM $VM + + if ((-not $ToolsVersion) -and (-not $ToolsRunningStatus) -and (-not $ToolsVersionStatus)) { + Throw "Please specify at lease one parameter: ToolsVersion, ToolsRunningStatus or ToolsVersionStatus" + } + + if ($ToolsVersion) { + $vmList = $vmList | Where {$_.Guest.ToolsVersion -like $ToolsVersion} + } + + if ($ToolsRunningStatus) { + $vmList = $vmList | Where {$_.Guest.ExtensionData.ToolsRunningStatus -eq $ToolsRunningStatus} + } + + if ($ToolsVersionStatus) { + $vmList = $vmList | Where {$_.Guest.ExtensionData.ToolsVersionStatus -eq $ToolsVersionStatus} + } + + $vmList + } +} + +Function Set-VMToolsUpgradePolicy { +<# +.SYNOPSIS + This cmdlet sets the VMTool's upgrade policy to "upgradeAtPowerCycle". + +.DESCRIPTION + This cmdlet sets the VMTool's upgrade policy to "upgradeAtPowerCycle" of specified virtual machines. + +.PARAMETER VM + Specifies the virtual machines which you want to set the VMTool's upgrade policy of. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password + C:\PS> Get-VM -Server $VCServer | Set-VMToolsUpgradePolicy + + Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of all virtual machines in the $VCServer vCetner Server. + +.EXAMPLE + C:\PS> Get-VM "*win*" | Set-VMToolsUpgradePolicy + + Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of virtual machines with name containing "win". + +.EXAMPLE + C:\PS> Get-VM -Location "MyClusterName" | Set-VMToolsUpgradePolicy + + Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of virtual machines in the "MyClusterName" cluster. + +.EXAMPLE + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Set-VMToolsUpgradePolicy + + Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of virtual machines on the "MyESXiHostName" ESXi host. + +.NOTES + This cmdlet assumes that you are connected to at least one vCenter Server system. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM + ) + Begin { + $UpgradePolicy = "upgradeAtPowerCycle" + $vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec + $vmConfigSpec.Tools = New-Object VMware.Vim.ToolsConfigInfo + $vmConfigSpec.Tools.ToolsUpgradePolicy = $UpgradePolicy + } + + Process { + foreach ($_ in $VM) { + # Get current setting + $vmView = Get-View $_ -Property Config.Tools.ToolsUpgradePolicy + # Change if VMTools upgrade policy is not "upgradeAtPowerCycle" + if ($vmView.Config.Tools.ToolsUpgradePolicy -ne $UpgradePolicy) { + Write-Verbose "Applying 'upgradeAtPowerCycle' setting to $($_.Name)..." + $vmView.ReconfigVM($vmConfigSpec) + } + } + } +} + +Function Invoke-VMToolsListProcessInVM { +<# +.Synopsis + This cmdlet lists the processes in the virtual machine. + +.Description + This cmdlet lists the running processes in the virtual machine. + +.PARAMETER VM + Specifies the virtual machine which you want to list the processes of. + +.Parameter GuestUser + Specifies the user name you want to use for authenticating with the guest OS. + +.Parameter GuestPassword + Specifies the password you want to use for authenticating with the guest OS. + +.Example + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $SampleVM = get-vm "MyVMName" + C:\PS> Invoke-VMToolsListProcessInVM -VM $SampleVM -GuestUser -GuestPassword + + ScriptOutput + ----------------------------------------------------------------------------------------------------------------------- + | USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND + | root 1 0.0 0.0 19360 1556 ? Ss Jul20 0:02 /sbin/init + | root 2 0.0 0.0 0 0 ? S Jul20 0:00 [kthreadd] + | root 3 0.0 0.0 0 0 ? S Jul20 0:06 [migration/0] + | root 4 0.0 0.0 0 0 ? S Jul20 0:00 [ksoftirqd/0] + | root 5 0.0 0.0 0 0 ? S Jul20 0:00 [stopper/0] + ...... + + List the processes in the "MyVMName" VM. + +.NOTES + This cmdlet lists processes in the guest OS of virtual machine. + A VMTools should already be running in the guest OS. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 + Guest OS : RHEL6.8, Windows7 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [String] $GuestUser, + + [Parameter(Mandatory=$true)] + [AllowEmptyString()] + [String] $GuestPassword + ) + + Process { + $vmView = Get-VM $VM | Get-View -Property Guest + if ($vmView.Guest.State -eq 'NotRunning') { + Write-Error "$VM is Not Running, unable to list the processes!" + return + } + + if ($vmView.Guest.GuestFamily -match 'windows') { + $command = 'Get-Process' + } elseif ($vmView.Guest.GuestFamily -match 'linux') { + $command = 'ps aux' + } else { + $command = 'ps' + } + + Invoke-VMScript -VM $VM -ScriptText $command -GuestUser $GuestUser -GuestPassword $GuestPassword + } +} + +Function Update-VMToolsImageLocation { +<# +.Synopsis + This cmdlet updates the link /productLocker in ESXi host. + +.Description + This cmdlet updates the link /productLocker in ESXi host directly to avoid host reboot. + +.Parameter VMHost + Specifies the ESXi host on which you want to update the /productLocker link. + +.Parameter HostUser + Specifies the user name you want to use for authenticating with the ESXi host. + +.Parameter HostPassword + Specifies the password you want to use for authenticating with the ESXi host. + +.Parameter ImageLocation + Specifies the new image location where you want /producterLocker to link. + +.Example + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $SampleHost = get-vmhost + C:\PS> Update-VMToolsImageLocation -VmHost $SampleHost -HostUser 'root' -HostPassword -ImageLocation '/locker/packages/6.5.0/' + + Update link /productLocker successfully. + + Update the link /producterLocker on $SampleHost to point to '/locker/packages/6.5.0/'. + +.NOTES + This cmdlet connects to ESXi host to execute shell command directly. + Make sure the SSH service on ESXi host is enabled, and a SSH library(Posh-SSH or SSH-Sessions etc.) + for powershell is already installed on client where you call This cmdlet. + You can instal Posh-SSH by executing: + iex (New-Object Net.WebClient).DownloadString("https://gist.github.com/darkoperator/6152630/raw/c67de4f7cd780ba367cccbc2593f38d18ce6df89/instposhsshdev") + For SSH-Sessions installation and usage, please refer to + http://www.powershelladmin.com/wiki/SSH_from_PowerShell_using_the_SSH.NET_library + + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VMHost] $VMHost, + + [Parameter(Mandatory=$true)] + [String] $HostUser, + + [Parameter(Mandatory=$true)] + [AllowEmptyString()] + [String] $HostPassword, + + [Parameter(Mandatory=$true)] + [String] $ImageLocation + ) + + Process { + if (-not (Get-Command New-SSHSession)) { + Throw "This cmdlet depends on SSH library. Please ensure a SSH library is already installed!" + } + + $password = new-object System.Security.SecureString + if ($HostPassword) { + $password = ConvertTo-SecureString -AsPlainText $HostPassword -Force + } + + $crendential = New-Object System.Management.Automation.PSCredential -ArgumentList $HostUser, $password + $sshSession = New-SSHSession -ComputerName $VMHost -Credential $crendential -Force + + $result = Invoke-SshCommand -SSHSession $sshSession -Command "readlink /productLocker" -EnsureConnection:$false + Write-Verbose "The link /productLocker before change: $($result.Output)" + + $command = "rm /productLocker && ln -s $ImageLocation /productLocker" + Write-Verbose "Updating /productLocker on $VMHost..." + $result = Invoke-SshCommand -SSHSession $sshSession -Command $command -EnsureConnection:$false + if ($result.ExitStatus -eq 0) { + Write-Host "Update link /productLocker successfully." -ForegroundColor Green + } else { + Write-Error "Failed to update link /productLocker: $($result.Error)" + } + + $result = Invoke-SshCommand -SSHSession $sshSession -Command "readlink /productLocker" -EnsureConnection:$false + Write-Verbose "The link /productLocker after change: $($result.Output)" + } +} + +Function Update-VMToolsConfInVM { +<# +.Synopsis + This cmdlet updates the tools.conf content in guest OS. + +.Description + This cmdlet copies the tools.conf in gueset OS of virtual machine to localhost, + then updates it locally by setting "vmtoolsd.level = info" and copies it back to the guest OS. + +.PARAMETER VM + Specifies the virtual machine to update. + +.Parameter GuestUser + Specifies the user name you want to use for authenticating with the guest OS. + +.Parameter GuestPassword + Specifies the password you want to use for authenticating with the guest OS. + +.Example + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $SampleVM = get-vm "MyVMName" + C:\PS> Update-VMToolsConfInVM -VM $SampleVM -GuestUser -GuestPassword + + Update tools.conf of 111394-RHEL-6.8-0 successfully. + + Updates the tools.conf in $SampleVM, changes the vmtoolsd log level to info ("vmtoolsd.level = info") for example. + +.NOTES + This cmdlet updates the tools.conf in guest OS. A VMTools should already be running in the guest OS. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM, + + [Parameter(Mandatory=$true)] + [String] $GuestUser, + + [Parameter(Mandatory=$true)] + [AllowEmptyString()] + [String] $GuestPassword + ) + + Process { + $vmGuest = Get-VMGuest $VM + $OsName = $vmGuest.OSFullName + $guestToolsConfFile = "" + $localToolsConfFile = ".\tools.conf" + + # Determine the tools.conf path in guest OS + if (($OsName -match "Linux") ` + -or ($OsName -match "FreeBSD") ` + -or ($OsName -match "Solaris")) { + $guestToolsConfFile = '/etc/vmware-tools/tools.conf' + } elseif (($OsName -match "Windows Server 2003") ` + -or ($OsName -match "Windows Server 2000") ` + -or ($OsName -match "Windows XP")) { + $guestToolsConfFile = 'C:\Documents and Settings\All Users\Application Data\VMware\VMware Tools\tools.conf' + } elseif ($OsName -match "Windows") { + $guestToolsConfFile = 'C:\ProgramData\VMware\VMware Tools\tools.conf' + } elseif ($OsName -match "Mac") { + $guestToolsConfFile = '/Library/Application Support/VMware Tools/tools.conf' + } else { + Throw "Unknown tools.conf path on OS: $OsName" + } + + # Get the tools.conf from guest OS to localhost, ignore the error if tools.conf was not found in guest OS + Write-Verbose "Copy tools.conf from $VM to localhost..." + $lastError = $Error[0] + Copy-VMGuestFile -Source $guestToolsConfFile -Destination $localToolsConfFile -VM $VM -GuestToLocal ` + -GuestUser $GuestUser -GuestPassword $GuestPassword -Force -ErrorAction:SilentlyContinue + + # The tools.conf doesn't exist in guest OS, create an empty one locally + if (($Error[0] -ne $lastError) -and ($Error[0] -notmatch 'tools.conf was not found')) { + Write-Error "Failed to copy tools.conf from $VM" + return + } elseif (-not (Test-Path $localToolsConfFile)) { + Set-Content $localToolsConfFile $null + } + + ############################################################################# + # Updates tools.conf by setting vmtoolsd.level = info, just for example. + ############################################################################# + $confContent = Get-Content $localToolsConfFile + $updatedContent = "vmtoolsd.level = info" + + Write-Verbose "Editing tools.conf (set 'vmtoolsd.level = info' for example)..." + if ($confContent -match "vmtoolsd\.level") { + $confContent -replace "vmtoolsd\.level.*", $updatedContent | Set-Content $localToolsConfFile + } elseif ($confContent -match "logging") { + Add-Content $localToolsConfFile $updatedContent + } else { + Add-Content $localToolsConfFile "[logging]`nlog=true" + Add-Content $localToolsConfFile $updatedContent + } + + # Upload the changed tools.conf to guest OS + try { + Write-Verbose "Copy local tools.conf to $VM..." + Copy-VMGuestFile -Source $localToolsConfFile -Destination $guestToolsConfFile -VM $VM -LocalToGuest ` + -GuestUser $GuestUser -GuestPassword $GuestPassword -Force -ErrorAction:Stop + } catch { + Write-Error "Failed to update tools.conf of $VM" + return + } + Write-Host "The tools.conf updated in $VM successfully." -ForegroundColor Green + } +} + +Function Invoke-VMToolsVIBInstall { +<# +.SYNOPSIS + This cmdlet installs VMTool VIB in ESXi hosts. + +.DESCRIPTION + This cmdlet installs VMTool VIB in specified ESXi hosts. + +.PARAMETER VMHost + Specifies the ESXi hosts which you want to install VMTool VIB in. + +.PARAMETER ToolsVibUrl + Specifies the URL of VMTools VIB package which you want to install in ESXi hosts. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password . + C:\PS> $viBurl = "http:///VMware_locker_tools-light_6.5.0-10.2.0.6085460.vib" + C:\PS> Get-VMHost -Server $VCServer | Invoke-VMToolsVIBInstall -ToolsVibUrl $viBurl + + Install VMTool VIB in $VCServer. + +.EXAMPLE + C:\PS> Invoke-VMToolsVIBInstall -VMHost "MyESXiHostName" -ToolsVibUrl $viBurl + + Installs VMTools VIB package successfully. + + Installs VMTool VIB in the "MyESXiHostName" ESXi host. + +.EXAMPLE + C:\PS> Get-VMHost -Location "MyClusterName" | Invoke-VMToolsVIBInstall -ToolsVibUrl $vib + + Installs VMTool VIB in ESXi host of the "MyClusterName" cluster. + +.NOTES + This cmdlet assumes that you are connected to at least one vCenter Server system. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VMHost[]] $VMHost, + + [Parameter(Mandatory=$true)] + [String] $ToolsVibUrl + ) + + Process { + foreach ($_ in $VMHost) { + $esxcli = Get-EsxCLI -VMHost $_ -V2 + + $result = $esxcli.software.vib.list.Invoke() | where {$_.name -match 'tools'} + Write-Verbose "Existing tools VIB on $_ before installing: $($result.Name)_$($result.Version)" + + # Install VIBs + Write-Verbose "Installing $ToolsVibUrl on $($_.Name)..." + $Error.Clear() + $cliArgs = $esxcli.software.vib.install.CreateArgs() + $cliArgs.viburl = $ToolsVibUrl + $cliArgs.nosigcheck = $true + $cliArgs.force = $true + $result = $esxcli.software.vib.install.Invoke($cliArgs) + if ($Error) { + Write-Error "Failed to install VMTools VIB package!" + } else { + Write-Verbose $result.Message + $result = $esxcli.software.vib.list.Invoke() | where {$_.name -match 'tools'} + Write-Verbose "Tools VIB on $_ after installing: $($result.Name)_$($result.Version)" + Write-Host "VMTools VIB package installed on $_ successfully." -ForegroundColor Green + } + } + } +} + +Function Invoke-VMToolsUpgradeInVMs { +<# +.SYNOPSIS + This cmdlet upgrades VMTools to the version bundled by ESXi host. + +.DESCRIPTION + This cmdlet upgrades VMTools of specified virtual machines to the version + bundled by ESXi host. You can also specify the number of virtual machines + to upgrade in parallel. + +.PARAMETER VM + Specifies the virtual machines you want to upgrade VMTools of. + +.PARAMETER GuestOSType + Specifies the guest OS type of the virtual machines. + +.PARAMETER VersionToUpgrade + Specifies the current running VMTools version of virtual machines. + +.PARAMETER MaxParallelUpgrades + Specifies the max virtual machine numbers to upgrade in parallel. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password + C:\PS> Get-VM -Server $VCServer | Invoke-VMToolsUpgradeInVMs -MaxParallelUpgrades 5 + + Upgrades VMTools of all virtual machines in the $VCServer vCetner Server, 5 at a time in parallel. + +.EXAMPLE + C:\PS> Get-VM | Invoke-VMToolsUpgradeInVMs -GuestOSType windows -MaxParallelUpgrades 1 | ft -Autosize + + Upgrade result: + + VmName UpgradeResult ToolsVersion ToolsVersionStatus TotalSeconds Message + ------ ------------- ------------ ------------------ ------------ ------- + 111167-Win-7-Sp1-64-Enterprise-NoTools-2 Completed 10.1.0 guestToolsCurrent 102 Upgrade VMTools successfully + 111393-RHEL-Server-7.2 Skipped 10.0.0 guestToolsNeedUpgrade 0 Guest OS type does not meet condtion 'windows' + 111305-Windows-Server2016 Completed 10.1.0 guestToolsCurrent 144 Upgrade VMTools successfully + + Upgrades VMTools of windows virtual machines one by one. + +.EXAMPLE + C:\PS> Get-VM -Location "MyClusterName" | Invoke-VMToolsUpgradeInVMs -MaxParallelUpgrades 2 | ft -Autosize + + Upgrade result: + + VmName UpgradeResult ToolsVersion ToolsVersionStatus TotalSeconds Message + ------ ------------- ------------ ------------------ ------------ ------- + 111167-Win-7-Sp1-64-Enterprise-NoTools-2 Failed 10.0.0 guestToolsNeedUpgrade 0 The required VMware Tools ISO image does not exist or is inaccessible. + 111393-RHEL-Server-7.2 Completed 10.1.0 guestToolsCurrent 100 Upgrade VMTools successfully + + Upgrades VMTools of virtual machines in the "MyClusterName" cluster, 2 at a time. + +.EXAMPLE + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Invoke-VMToolsUpgradeInVMs -MaxParallelUpgrades 5 + + Upgrades VMTools of virtual machines on the "MyESXiHostName" ESXi host, 5 at a time. + +.NOTES + This cmdlet assumes an old VMTools is already running in the virtual machine. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM, + + [Parameter(Mandatory=$false)] + [ValidateSet("linux", "windows")] + [String] $GuestOSType, + + [Parameter(Mandatory=$false)] + [String] $VersionToUpgrade, + + [Parameter(Mandatory=$false)] + [ValidateRange(1, 5)] + [Int] $MaxParallelUpgrades = 1 + ) + + Begin { + $RunspacePool = [runspacefactory]::CreateRunspacePool( + 1, #Min Runspaces + $MaxParallelUpgrades #Max Runspaces + ) + + $RunspacePool.Open() + + $jobs = New-Object System.Collections.ArrayList + $result = @() + } + + Process { + foreach ($_ in $VM) { + $vmView = Get-View $_ -Property Guest + $toolsVersion = $_.Guest.ToolsVersion + $toolsVersionStatus = $vmView.Guest.ToolsVersionStatus + + # Skip if VMTools doesn't need to upgrade + if ($toolsVersionStatus -ne "guestToolsNeedUpgrade") { + Write-Host "No VMTools need to upgrade!`nVM: '$_', ToolsVersionStatus: '$toolsVersionStatus'" + $result += [pscustomobject]@{ + VmName = $_.Name + UpgradeResult = "Skipped" + ToolsVersion = $toolsVersion + ToolsVersionStatus = $toolsVersionStatus + TotalSeconds = 0 + Message = "No VMTools need to upgrade!" + } + continue + } + + # Skip if current VMTools doesn't meet to specified version + if ($VersionToUpgrade -and ($toolsVersion -notmatch $VersionToUpgrade)) { + Write-Host "Current ToolsVersion in $_ is: $toolsVersion,"` + "does not meet condtion `'$VersionToUpgrade`', skipping it..." -ForegroundColor Yellow + $result += [pscustomobject]@{ + VmName = $_.Name + UpgradeResult = "Skipped" + ToolsVersion = $toolsVersion + ToolsVersionStatus = $toolsVersionStatus + TotalSeconds = 0 + Message = "Current VMTools version does not meet condtion `'$VersionToUpgrade`'" + } + continue + } + + # Create a thread to upgrade VMTools for each virtual machine + $PSThread = [powershell]::Create() + $PSThread.RunspacePool = $RunspacePool + + # Script content to upgrade VMTools + $PSThread.AddScript({ + Param ( + $vcServer, + $session, + $vmId, + $GuestOSType + ) + # Load PowerCLI module and connect to VCServer, as child thread environment is independent with parent + if(-not $global:DefaultVIServer) { + $moduleName = "vmware.vimautomation.core" + if(-not (Get-Module | Where {$_.name -eq $moduleName})) { + try { + Import-Module $moduleName -ErrorAction SilentlyContinue | Out-Null + } + catch { + Throw "Failed to load PowerCLI module('$moduleName')" + } + } + try { + $server = Connect-VIServer -Server $vcserver -session $session -Force + } + catch { + Throw "Failed to connect to VI server: $vcserver" + } + } + + # Retrieves VM + $vm = Get-VM -Id $vmId + + $ThreadID = [appdomain]::GetCurrentThreadId() + Write-Verbose “Thread[$ThreadID]: Beginning Update-Tools for $vm” + + if ($vm.PowerState -ne 'PoweredOn') { + Write-Host "Powering on VM: $vm..." + Start-VM $vm | Out-Null + $vm = Get-VM $vm + } + + # Wait for OS and VMTools starting up + $timeOut = 60*10 #seconds + $refreshInterval = 5 #seconds + $count = $timeOut/$refreshInterval + while (($vm.Guest.ExtensionData.ToolsRunningStatus -ne "guestToolsRunning") ` + -or (-not $vm.Guest.GuestFamily)) { + $count -= 1 + if ($count -lt 0) { + Write-Error "VMTools doesn't start up in $timeOut seconds, please check if $vm is hung!" + break + } + Write-Verbose "Waiting for VMTools running in $vm before upgrading..." + Start-Sleep -Seconds $refreshInterval + } + + # Skip if virtual machine doesn't meet specified guest OS type + if ($GuestOSType -and ($vm.Guest.GuestFamily -notmatch $GuestOSType)) { + Write-Host "GuestFamily of $vm is: $($vm.Guest.GuestFamily),"` + "does not meet condition `'$GuestOSType`', skipping it..." -ForegroundColor Yellow + # upgrade result + [pscustomobject]@{ + VmName = $vm.Name + UpgradeResult = "Skipped" + ToolsVersion = $vm.Guest.ToolsVersion + ToolsVersionStatus = $vm.Guest.ExtensionData.ToolsVersionStatus + TotalSeconds = 0 + Message = "Guest OS type does not meet condtion `'$GuestOSType`'" + } + Disconnect-VIServer $server -Confirm:$false + return + } + + # Upgrade VMTools and check the tools version status + Write-Host "Upgrading VMTools for VM: $vm..." + $task = Update-Tools -VM $vm -RunAsync + $task | Wait-Task + $task = Get-Task -Id $task.Id + + if ($task.State -eq "Success") { + $upgradeResult = "Completed" + $message = "Upgrade VMTools successfully" + Write-Host "Upgrade VMTools successfully for VM: $vm" -ForegroundColor Green + } else { + $upgradeResult = "Failed" + $message = $task.ExtensionData.Info.Error.LocalizedMessage + Write-Error "Failed to upgrade VMTools for VM: $vm" + } + $vm = Get-VM $vm + # Upgrade result to return + [pscustomobject]@{ + VmName = $vm.Name + UpgradeResult = $upgradeResult + ToolsVersion = $vm.Guest.ToolsVersion + ToolsVersionStatus = $vm.Guest.ExtensionData.ToolsVersionStatus + TotalSeconds = [math]::Floor(($task.FinishTime).Subtract($task.StartTime).TotalSeconds) + Message = $message + } + Write-Verbose “Thread[$ThreadID]: Ending Update-Tools for $vm” + }) | Out-Null + $vc = $Global:DefaultVIServer.ServiceUri.Host + $vcSession = $Global:DefaultVIServer.SessionSecret + $PSThread.AddArgument($vc).AddArgument($vcSession).AddArgument($_.Id).AddArgument($GuestOSType) | Out-Null + + # Start thread + $Handle = $PSThread.BeginInvoke() + $job = New-Object System.Object + $job | Add-Member -type NoteProperty -name Thread -value $PSThread + $job | Add-Member -type NoteProperty -name Handle -value $Handle + $jobs.Add($job) | Out-Null + + Write-Verbose (“Available Runspaces in RunspacePool: {0}” -f $RunspacePool.GetAvailableRunspaces()) + } + } + + End { + #Verify all threads completed + while (($jobs | Where {$_.Handle.iscompleted -ne ‘Completed’}).Count -gt 0) { + Start-Sleep -Seconds 5 + } + + $upgradeResult = $jobs | foreach { + $_.Thread.EndInvoke($_.Handle) + $_.Thread.Dispose() + } + $result += $upgradeResult + $result + + $RunspacePool.Close() + $RunspacePool.Dispose() + } +} + +Export-ModuleMember *-* \ No newline at end of file From 9f2fc3ec065cb451317a2cbb9f9e66691b7fe55e Mon Sep 17 00:00:00 2001 From: William Lam Date: Tue, 14 Nov 2017 06:25:50 -0800 Subject: [PATCH 16/28] Adding several new Content Library functions --- Modules/ContentLibrary/ContentLibrary.psm1 | 386 ++++++++++++++++++++- 1 file changed, 385 insertions(+), 1 deletion(-) diff --git a/Modules/ContentLibrary/ContentLibrary.psm1 b/Modules/ContentLibrary/ContentLibrary.psm1 index 824cb16..da83745 100644 --- a/Modules/ContentLibrary/ContentLibrary.psm1 +++ b/Modules/ContentLibrary/ContentLibrary.psm1 @@ -25,12 +25,29 @@ $results = @() foreach($libraryID in $libaryIDs) { - $library = $contentLibaryService.get($libraryId) + $library = $contentLibaryService.get($libraryID) # Use vCenter REST API to retrieve name of Datastore that is backing the Content Library $datastoreService = Get-CisService com.vmware.vcenter.datastore $datastore = $datastoreService.get($library.storage_backings.datastore_id) + if($library.publish_info.published) { + $published = $library.publish_info.published + $publishedURL = $library.publish_info.publish_url + $externalReplication = $library.publish_info.persist_json_enabled + } else { + $published = $library.publish_info.published + $publishedURL = "N/A" + $externalReplication = "N/A" + } + + if($library.subscription_info) { + $subscribeURL = $library.subscription_info.subscription_url + $published = "N/A" + } else { + $subscribeURL = "N/A" + } + if(!$LibraryName) { $libraryResult = [pscustomobject] @{ Id = $library.Id; @@ -38,6 +55,10 @@ Type = $library.Type; Description = $library.Description; Datastore = $datastore.name; + Published = $published; + PublishedURL = $publishedURL; + JSONPersistence = $externalReplication; + SubscribedURL = $subscribeURL; CreationTime = $library.Creation_Time; } $results+=$libraryResult @@ -49,6 +70,10 @@ Type = $library.Type; Description = $library.Description; Datastore = $datastore.name; + Published = $published; + PublishedURL = $publishedURL; + JSONPersistence = $externalReplication; + SubscribedURL = $subscribeURL; CreationTime = $library.Creation_Time; } $results+=$libraryResult @@ -194,4 +219,363 @@ Function Get-ContentLibraryItemFiles { } } $results +} + +Function Set-ContentLibrary { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function updates the JSON Persistence property for a given Content Library + .PARAMETER LibraryName + The name of a vSphere Content Library + .EXAMPLE + Set-ContentLibraryItems -LibraryName Test -JSONPersistenceEnabled + .EXAMPLE + Set-ContentLibraryItems -LibraryName Test -JSONPersistenceDisabled +#> + param( + [Parameter(Mandatory=$true)][String]$LibraryName, + [Parameter(Mandatory=$false)][Switch]$JSONPersistenceEnabled, + [Parameter(Mandatory=$false)][Switch]$JSONPersistenceDisabled + ) + + $contentLibaryService = Get-CisService com.vmware.content.library + $libaryIDs = $contentLibaryService.list() + + $found = $false + foreach($libraryID in $libaryIDs) { + $library = $contentLibaryService.get($libraryId) + if($library.name -eq $LibraryName) { + $found = $true + break + } + } + + if($found) { + $localLibraryService = Get-CisService -Name "com.vmware.content.local_library" + + if($JSONPersistenceEnabled) { + $jsonPersist = $true + } else { + $jsonPersist = $false + } + + $updateSpec = $localLibraryService.Help.update.update_spec.Create() + $updateSpec.type = $library.type + $updateSpec.publish_info.authentication_method = $library.publish_info.authentication_method + $updateSpec.publish_info.persist_json_enabled = $jsonPersist + Write-Host "Updating JSON Persistence configuration setting for $LibraryName ..." + $localLibraryService.update($library.id,$updateSpec) + } else { + Write-Host "Unable to find Content Library $Libraryname" + } +} + +Function New-ExtReplicatedContentLibrary { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function creates a new Subscriber Content Library from a JSON Persisted + Content Library that has been externally replicated + .PARAMETER LibraryName + The name of the new vSphere Content Library + .PARAMETER DatastoreName + The name of the vSphere Datastore which contains JSON Persisted configuration file + .PARAMETER SubscribeLibraryName + The name fo the root directroy of the externally replicated Content Library residing on vSphere Datastore + .PARAMETER AutoSync + Whether or not to Automatically sync content + .PARAMETER OnDemand + Only sync content when requested + .EXAMPLE + New-ExtReplicatedContentLibrary -LibraryName Bar -DatastoreName iSCSI-02 -SubscribeLibraryName myExtReplicatedLibrary + .EXAMPLE + New-ExtReplicatedContentLibrary -LibraryName Bar -DatastoreName iSCSI-02 -SubscribeLibraryName myExtReplicatedLibrary -AutoSync $false -OnDemand $true +#> + param( + [Parameter(Mandatory=$true)][String]$LibraryName, + [Parameter(Mandatory=$true)][String]$DatastoreName, + [Parameter(Mandatory=$true)][String]$SubscribeLibraryName, + [Parameter(Mandatory=$false)][Boolean]$AutoSync=$false, + [Parameter(Mandatory=$false)][Boolean]$OnDemand=$true + ) + + $datastore = Get-Datastore -Name $DatastoreName + + if($datastore) { + $datastoreId = $datastore.ExtensionData.MoRef.Value + $datastoreUrl = $datastore.ExtensionData.Info.Url + $subscribeUrl = $datastoreUrl + $SubscribeLibraryName + "/lib.json" + + $subscribeLibraryService = Get-CisService -Name "com.vmware.content.subscribed_library" + + $StorageSpec = [pscustomobject] @{ + datastore_id = $datastoreId; + type = "DATASTORE"; + } + + $UniqueChangeId = [guid]::NewGuid().tostring() + + $createSpec = $subscribeLibraryService.Help.create.create_spec.Create() + $createSpec.name = $LibraryName + $addResults = $createSpec.storage_backings.Add($StorageSpec) + $createSpec.subscription_info.automatic_sync_enabled = $false + $createSpec.subscription_info.on_demand = $true + $createSpec.subscription_info.subscription_url = $subscribeUrl + $createSpec.subscription_info.authentication_method = "NONE" + $createSpec.type = "SUBSCRIBED" + Write-Host "Creating new Externally Replicated Content Library called $LibraryName ..." + $library = $subscribeLibraryService.create($UniqueChangeId,$createSpec) + } +} + +Function Remove-SubscribedContentLibrary { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function deletes a Subscriber Content Library + .PARAMETER LibraryName + The name of the new vSphere Content Library to delete + .EXAMPLE + Remove-SubscribedContentLibrary -LibraryName Bar +#> + param( + [Parameter(Mandatory=$true)][String]$LibraryName + ) + + $contentLibaryService = Get-CisService com.vmware.content.library + $libaryIDs = $contentLibaryService.list() + + $found = $false + foreach($libraryID in $libaryIDs) { + $library = $contentLibaryService.get($libraryId) + if($library.name -eq $LibraryName) { + $found = $true + break + } + } + + if($found) { + $subscribeLibraryService = Get-CisService -Name "com.vmware.content.subscribed_library" + + Write-Host "Deleting Subscribed Content Library $LibraryName ..." + $subscribeLibraryService.delete($library.id) + } else { + Write-Host "Unable to find Content Library $LibraryName" + } +} + +Function New-LocalContentLibrary { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function creates a new Subscriber Content Library from a JSON Persisted + Content Library that has been externally replicated + .PARAMETER LibraryName + The name of the new vSphere Content Library + .PARAMETER DatastoreName + The name of the vSphere Datastore to store the Content Library + .PARAMETER Publish + Whther or not to publish the Content Library, this is required for JSON Peristence + .PARAMETER JSONPersistence + Whether or not to enable JSON Persistence which enables external replication of Content Library + .EXAMPLE + New-LocalContentLibrary -LibraryName Foo -DatastoreName iSCSI-01 -Publish $true + .EXAMPLE + New-LocalContentLibrary -LibraryName Foo -DatastoreName iSCSI-01 -Publish $true -JSONPersistence $true +#> + param( + [Parameter(Mandatory=$true)][String]$LibraryName, + [Parameter(Mandatory=$true)][String]$DatastoreName, + [Parameter(Mandatory=$false)][Boolean]$Publish=$true, + [Parameter(Mandatory=$false)][Boolean]$JSONPersistence=$false + ) + + $datastore = Get-Datastore -Name $DatastoreName + + if($datastore) { + $datastoreId = $datastore.ExtensionData.MoRef.Value + $localLibraryService = Get-CisService -Name "com.vmware.content.local_library" + + $StorageSpec = [pscustomobject] @{ + datastore_id = $datastoreId; + type = "DATASTORE"; + } + + $UniqueChangeId = [guid]::NewGuid().tostring() + + $createSpec = $localLibraryService.Help.create.create_spec.Create() + $createSpec.name = $LibraryName + $addResults = $createSpec.storage_backings.Add($StorageSpec) + $createSpec.publish_info.authentication_method = "NONE" + $createSpec.publish_info.persist_json_enabled = $JSONPersistence + $createSpec.publish_info.published = $Publish + $createSpec.type = "LOCAL" + Write-Host "Creating new Local Content Library called $LibraryName ..." + $library = $localLibraryService.create($UniqueChangeId,$createSpec) + } +} + +Function Remove-LocalContentLibrary { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function deletes a Local Content Library + .PARAMETER LibraryName + The name of the new vSphere Content Library to delete + .EXAMPLE + Remove-LocalContentLibrary -LibraryName Bar +#> + param( + [Parameter(Mandatory=$true)][String]$LibraryName + ) + + $contentLibaryService = Get-CisService com.vmware.content.library + $libaryIDs = $contentLibaryService.list() + + $found = $false + foreach($libraryID in $libaryIDs) { + $library = $contentLibaryService.get($libraryId) + if($library.name -eq $LibraryName) { + $found = $true + break + } + } + + if($found) { + $localLibraryService = Get-CisService -Name "com.vmware.content.local_library" + + Write-Host "Deleting Local Content Library $LibraryName ..." + $localLibraryService.delete($library.id) + } else { + Write-Host "Unable to find Content Library $LibraryName" + } +} + +Function Copy-ContentLibrary { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function copies all library items from one Content Library to another + .PARAMETER SourceLibaryName + The name of the source Content Library to copy from + .PARAMETER DestinationLibaryName + The name of the desintation Content Library to copy to + .PARAMETER DeleteSourceFile + Whther or not to delete library item from the source Content Library after copy + .EXAMPLE + Copy-ContentLibrary -SourceLibaryName Foo -DestinationLibaryName Bar + .EXAMPLE + Copy-ContentLibrary -SourceLibaryName Foo -DestinationLibaryName Bar -DeleteSourceFile $true +#> + param( + [Parameter(Mandatory=$true)][String]$SourceLibaryName, + [Parameter(Mandatory=$true)][String]$DestinationLibaryName, + [Parameter(Mandatory=$false)][Boolean]$DeleteSourceFile=$false + ) + + $sourceLibraryId = (Get-ContentLibrary -LibraryName $SourceLibaryName).Id + if($sourceLibraryId -eq $null) { + Write-Host -ForegroundColor red "Unable to find Source Content Library named $SourceLibaryName" + exit + } + $destinationLibraryId = (Get-ContentLibrary -LibraryName $DestinationLibaryName).Id + if($destinationLibraryId -eq $null) { + Write-Host -ForegroundColor Red "Unable to find Destination Content Library named $DestinationLibaryName" + break + } + + $sourceItemFiles = Get-ContentLibraryItems -LibraryName $SourceLibaryName + if($sourceItemFiles -eq $null) { + Write-Host -ForegroundColor red "Unable to retrieve Content Library Items from $SourceLibaryName" + break + } + + $contentLibaryItemService = Get-CisService com.vmware.content.library.item + + foreach ($sourceItemFile in $sourceItemFiles) { + # Check to see if file already exists in destination Content Library + $result = Get-ContentLibraryItems -LibraryName $DestinationLibaryName -LibraryItemName $sourceItemFile.Name + + if($result -eq $null) { + # Create CopySpec + $copySpec = $contentLibaryItemService.Help.copy.destination_create_spec.Create() + $copySpec.library_id = $destinationLibraryId + $copySpec.name = $sourceItemFile.Name + $copySpec.description = $sourceItemFile.Description + # Create random Unique Copy Id + $UniqueChangeId = [guid]::NewGuid().tostring() + + # Perform Copy + try { + Write-Host -ForegroundColor Cyan "Copying" $sourceItemFile.Name "..." + $copyResult = $contentLibaryItemService.copy($UniqueChangeId, $sourceItemFile.Id, $copySpec) + } catch { + Write-Host -ForegroundColor Red "Failed to copy" $sourceItemFile.Name + $Error[0] + break + } + + # Delete source file if set to true + if($DeleteSourceFile) { + try { + Write-Host -ForegroundColor Magenta "Deleteing" $sourceItemFile.Name "..." + #$deleteResult = $contentLibaryItemService.delete($sourceItemFile.Id) + } catch { + Write-Host -ForegroundColor Red "Failed to delete" $sourceItemFile.Name + $Error[0] + break + } + } + } else { + Write-Host -ForegroundColor Yellow "Skipping" $sourceItemFile.Name "already exists" + + # Delete source file if set to true + if($DeleteSourceFile) { + try { + Write-Host -ForegroundColor Magenta "Deleteing" $sourceItemFile.Name "..." + #$deleteResult = $contentLibaryItemService.delete($sourceItemFile.Id) + } catch { + Write-Host -ForegroundColor Red "Failed to delete" $sourceItemFile.Name + break + } + } + } + } } \ No newline at end of file From 2d429c62717c4fac6590625738ce6e2bf9cd7a4e Mon Sep 17 00:00:00 2001 From: William Lam Date: Tue, 14 Nov 2017 06:45:58 -0800 Subject: [PATCH 17/28] Forgot to un-comment the delete code --- Modules/ContentLibrary/ContentLibrary.psm1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/ContentLibrary/ContentLibrary.psm1 b/Modules/ContentLibrary/ContentLibrary.psm1 index da83745..e2fef41 100644 --- a/Modules/ContentLibrary/ContentLibrary.psm1 +++ b/Modules/ContentLibrary/ContentLibrary.psm1 @@ -556,7 +556,7 @@ Function Copy-ContentLibrary { if($DeleteSourceFile) { try { Write-Host -ForegroundColor Magenta "Deleteing" $sourceItemFile.Name "..." - #$deleteResult = $contentLibaryItemService.delete($sourceItemFile.Id) + $deleteResult = $contentLibaryItemService.delete($sourceItemFile.Id) } catch { Write-Host -ForegroundColor Red "Failed to delete" $sourceItemFile.Name $Error[0] @@ -570,7 +570,7 @@ Function Copy-ContentLibrary { if($DeleteSourceFile) { try { Write-Host -ForegroundColor Magenta "Deleteing" $sourceItemFile.Name "..." - #$deleteResult = $contentLibaryItemService.delete($sourceItemFile.Id) + $deleteResult = $contentLibaryItemService.delete($sourceItemFile.Id) } catch { Write-Host -ForegroundColor Red "Failed to delete" $sourceItemFile.Name break From a47369a29572e0b0458a3d81e1c31621688c1b56 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 20 Nov 2017 15:22:21 +0000 Subject: [PATCH 18/28] Minor Spelling corrections generted->generated Minor Spelling corrections generted->generated in Get-Help examples --- Modules/VMware.VMEncryption/VMware.VMEncryption.psm1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/VMware.VMEncryption/VMware.VMEncryption.psm1 b/Modules/VMware.VMEncryption/VMware.VMEncryption.psm1 index e91b0c5..023087c 100644 --- a/Modules/VMware.VMEncryption/VMware.VMEncryption.psm1 +++ b/Modules/VMware.VMEncryption/VMware.VMEncryption.psm1 @@ -882,7 +882,7 @@ Function Set-VMEncryptionKey { C:\PS>$VM|Set-VMEncryptionKey -KMSClusterId $KMSCluster.Id -Deep Deep rekeys the VM Home and all its disks using a new key. - The key is generted from the KMS whose clusterId is $KMSCluster.Id. + The key is generated from the KMS whose clusterId is $KMSCluster.Id. .NOTES This cmdlet assumes there is already a KMS in vCenter Server. If VM is not encrypted, the cmdlet quits. @@ -1037,7 +1037,7 @@ Function Set-VMDiskEncryptionKey { C:\PS>$HardDisk| Set-VMDiskEncryptionKey -VM $VM -KMSClusterId $KMSCluster.Id -Deep Deep rekeys all the disks of the $VM using a new key. - The key is generted from the KMS whose clusterId is $KMSCluster.Id. + The key is generated from the KMS whose clusterId is $KMSCluster.Id. .NOTES This cmdlet assumes there is already a KMS in vCenter Server. From dc6b02a95ae5f1f3ee7d53d6f7747682190e5345 Mon Sep 17 00:00:00 2001 From: William Lam Date: Tue, 21 Nov 2017 07:39:22 -0800 Subject: [PATCH 19/28] Export/Import functions for manual vCenter Server Migrations --- Modules/vCenterManualMigration.psm1 | 475 ++++++++++++++++++++++++++++ 1 file changed, 475 insertions(+) create mode 100644 Modules/vCenterManualMigration.psm1 diff --git a/Modules/vCenterManualMigration.psm1 b/Modules/vCenterManualMigration.psm1 new file mode 100644 index 0000000..a7750b9 --- /dev/null +++ b/Modules/vCenterManualMigration.psm1 @@ -0,0 +1,475 @@ +Function Export-DRSRules { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Export DRS Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Export DRS Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Export-DRSRules -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster +#> + param( + [Parameter(Mandatory=$false)][String]$Path, + [Parameter(Mandatory=$true)][String]$Cluster + ) + + $rules = Get-Cluster -Name $Cluster | Get-DrsRule + + $results = @() + foreach ($rule in $rules) { + $vmNames = @() + $vmIds = $rule.VMIds + + # Reconstruct MoRef ID to VM Object to get Name + foreach ($vmId in $vmIds) { + $vm = New-Object VMware.Vim.ManagedObjectReference + $vm.Type = "VirtualMachine" + $vm.Value = ($vmId -replace "VirtualMachine-","") + $vmView = Get-View $vm + $vmNames += $vmView.name + } + + $rulesObject = [pscustomobject] @{ + Name = $rule.ExtensionData.Name; + Type = $rule.Type; #VMAffinity = 1, VMAntiAffinity = 0 + Enabled = $rule.Enabled; + Mandatory = $rule.ExtensionData.Mandatory + VM = $vmNames + } + $results+=$rulesObject + } + if($Path) { + $fullPath = $Path + "\DRSRules.json" + Write-Host -ForegroundColor Green "Exporting DRS Rules to $fullpath ..." + $results | ConvertTo-Json | Out-File $fullPath + } else { + $results | ConvertTo-Json + } +} + +Function Import-DRSRules { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Import DRS Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Import DRS Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Import-DRSRules -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster +#> + param( + [Parameter(Mandatory=$true)][String]$Path, + [Parameter(Mandatory=$true)][String]$Cluster + ) + + Get-DrsRule -Cluster $cluster | Remove-DrsRule -Confirm:$false | Out-Null + + $DRSRulesFilename = "/DRSRules.json" + $fullPath = $Path + $DRSRulesFilename + $json = Get-Content -Raw $fullPath | ConvertFrom-Json + + foreach ($line in $json) { + $vmArr = @() + $vmNames = $line.vm + foreach ($vmName in $vmNames) { + $vmView = Get-VM -Name $vmName + $vmArr+=$vmView + } + New-DrsRule -Name $line.name -Enabled $line.Enabled -Cluster (Get-Cluster -Name $Cluster) -KeepTogether $line.Type -VM $vmArr + } +} + +Function Export-DRSClusterGroup { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Export DRS Cluster Group Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Export DRS Cluster Group Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Export-DRSClusterGroup -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster +#> + param( + [Parameter(Mandatory=$false)][String]$Path, + [Parameter(Mandatory=$true)][String]$Cluster + ) + + $rules = Get-Cluster -Name $Cluster | Get-DrsClusterGroup + + $results = @() + foreach ($rule in $rules) { + $rulesObject = [pscustomobject] @{ + Name = $rule.ExtensionData.Name; + Type = $rule.GroupType; #VMType = 1, HostType = 0 + Member = $rule.Member + } + $results+=$rulesObject + } + if($Path) { + $fullPath = $Path + "\DRSClusterGroupRules.json" + Write-Host -ForegroundColor Green "Exporting DRS Cluster Group Rules to $fullpath ..." + $results | ConvertTo-Json | Out-File $fullPath + } else { + $results | ConvertTo-Json + } +} + +Function Import-DRSClusterClusterGroup { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Import DRS Cluster Group Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Import DRS Cluster Group Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Import-DRSClusterClusterGroup -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster +#> + param( + [Parameter(Mandatory=$true)][String]$Path, + [Parameter(Mandatory=$true)][String]$Cluster + ) + + $DRSClusterGroupRulesFilename = "\DRSClusterGroupRules.json" + $fullPath = $Path + $DRSClusterGroupRulesFilename + $json = Get-Content -Raw $fullPath | ConvertFrom-Json + + foreach ($line in $json) { + $memberArr = @() + $members = $line.member + + # VMHost Group + if($line.Type -eq 0) { + foreach ($member in $members) { + $memberView = Get-VMhost -Name $member + $memberArr+=$memberView + } + New-DrsClusterGroup -Name $line.name -Cluster (Get-Cluster -Name $Cluster) -VMhost $memberArr + # VM Group + } else { + foreach ($member in $members) { + $memberView = Get-VM -Name $member + $memberArr+=$memberView + } + New-DrsClusterGroup -Name $line.name -Cluster (Get-Cluster -Name $Cluster) -VM $memberArr + } + } +} + +Function Export-Tag { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Export vSphere Tags and VM Assocations to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Export vSphere Tags and VM Assocations to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Export-Tag -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$false)][String]$Path + ) + + # Export Tag Categories + $tagCatagorys = Get-TagCategory + + $tagCatresults = @() + foreach ($tagCategory in $tagCatagorys) { + $tagCatObj = [pscustomobject] @{ + Name = $tagCategory.Name; + Cardinality = $tagCategory.Cardinality; + Description = $tagCategory.Description; + Type = $tagCategory.EntityType + } + $tagCatresults+=$tagCatObj + } + if($Path) { + $fullPath = $Path + "\AllTagCategory.json" + Write-Host -ForegroundColor Green "Exporting vSphere Tag Category to $fullpath ..." + $tagCatresults | ConvertTo-Json | Out-File $fullPath + } else { + $tagCatresults | ConvertTo-Json + } + + # Export Tags + $tags = Get-Tag + + $tagResults = @() + foreach ($tag in $tags) { + $tagObj = [pscustomobject] @{ + Name = $tag.Name; + Description = $tag.Description; + Category = $tag.Category.Name + } + $tagResults+=$tagObj + } + if($Path) { + $fullPath = $Path + "\AllTag.json" + Write-Host -ForegroundColor Green "Exporting vSphere Tag to $fullpath ..." + $tagResults | ConvertTo-Json | Out-File $fullPath + } else { + $tagResults | ConvertTo-Json + } + + # Export VM to Tag Mappings + $vms = Get-VM + + $vmResults = @() + foreach ($vm in $vms) { + $tagAssignments = $vm | Get-TagAssignment + $tags = @() + foreach ($tagAssignment in $tagAssignments) { + $tag = $tagAssignment.Tag + $tagName = $tag -split "/" + $tags+=$tagName + } + $vmObj = [pscustomobject] @{ + Name = $vm.name; + Tag = $tags + } + $vmResults+=$vmObj + } + if($Path) { + $fullPath = $Path + "\AllTagAssocations.json" + Write-Host -ForegroundColor Green "Exporting VM to vSphere Tag Assignment to $fullpath ..." + $vmResults | ConvertTo-Json | Out-File $fullPath + } else { + $vmResults | ConvertTo-Json + } +} + +Function Import-Tag { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Import vSphere Tags and VM Assocations from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Import vSphere Tags and VM Assocations from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Import-Tag -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$true)][String]$Path + ) + + $tagCatFilename = "\AllTagCategory.json" + $fullPath = $Path + $tagCatFilename + $tagCategoryJson = Get-Content -Raw $fullPath | ConvertFrom-Json + + $tagFilename = "\AllTag.json" + $fullPath = $Path + $tagFilename + $tagJson = Get-Content -Raw $fullPath | ConvertFrom-Json + + $vmTagFilename = "\AllTagAssocations.json" + $fullPath = $Path + $vmTagFilename + $vmTagJson = Get-Content -Raw $fullPath | ConvertFrom-Json + + # Re-Create Tag Category + foreach ($category in $tagCategoryJson) { + if($category.Cardinality -eq 0) { + $cardinality = "Single" + } else { + $cardinality = "Multiple" + } + New-TagCategory -Name $category.Name -Cardinality $cardinality -Description $category.Description -EntityType $category.Type + } + + # Re-Create Tags + foreach ($tag in $tagJson) { + New-Tag -Name $tag.Name -Description $tag.Description -Category (Get-TagCategory -Name $tag.Category) + } + + # Re-Create VM to Tag Mappings + foreach ($vmTag in $vmTagJson) { + $vm = Get-VM -Name $vmTag.name + $tags = $vmTag.Tag + foreach ($tag in $tags) { + New-TagAssignment -Entity $vm -Tag (Get-Tag -Name $tag) + } + } +} + +Function Export-VMFolder { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Export vSphere Folder to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Export vSphere Folder to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Export-VMFolder -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$false)][String]$Path + ) + $vms = Get-VM + + $vmFolderResults = @() + foreach ($vm in $vms) { + $vmFolderObj = [pscustomobject] @{ + Name = $vm.name; + Folder = $vm.Folder.Name; + } + $vmFolderResults+=$vmFolderObj + } + if($Path) { + $fullPath = $Path + "\AllVMFolder.json" + Write-Host -ForegroundColor Green "Exporting VM Folders to $fullpath ..." + $vmFolderResults | ConvertTo-Json | Out-File $fullPath + } else { + $vmFolderResults | ConvertTo-Json + } +} + +Function Import-VMFolder { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Import vSphere Folder from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Import vSphere Folder from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Import-VMFolder -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$true)][String]$Path + ) + + $vmFolderFilename = "\AllVMFolder.json" + $fullPath = $Path + $vmFolderFilename + $vmFolderJson = Get-Content -Raw $fullPath | ConvertFrom-Json + + # Root vm Folder + $rootVMFolder = Get-Folder -Type VM -Name vm + + $folders = $vmFolderJson | Select Folder | Sort-Object -Property Folder -Unique + foreach ($folder in $folders) { + $rootVMFolder | New-Folder -Name $folder.folder + } + + foreach ($vmFolder in $vmFolderJson) { + $vm = Get-VM -Name $vmFolder.Name + $folder = Get-Folder -Name $vmFolder.Folder + Move-VM -VM $vm -Destination $folder + } +} + +Function Export-VMStoragePolicy { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Export VM Storage Policies to JSON file + .DESCRIPTION + Export VM Storage Policies to JSON file + .EXAMPLE + Export-VMStoragePolicy -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$false)][String]$Path + ) + + foreach ($policy in Get-SpbmStoragePolicy) { + $policyName = $policy.Name + if($Path) { + Write-Host -ForegroundColor Green "Exporting Policy $policyName to $Path\$policyName.xml ..." + $policy | Export-SpbmStoragePolicy -FilePath $Path\$policyName.xml -Force | Out-Null + } else { + $policy + } + } +} + +Function Import-VMStoragePolicy { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Import VM Storage Policies from JSON file + .DESCRIPTION + Import VM Storage Policies from JSON file + .EXAMPLE + Import-VMStoragePolicy -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$false)][String]$Path + ) + + foreach ($file in Get-ChildItem -Path $Path -Filter *.xml) { + $policyName = $file.name + $policyName = $policyName.replace(".xml","") + if(Get-SpbmStoragePolicy -Name $policyName -ErrorAction SilentlyContinue) { + Continue + } else { + Write-Host "Importing Policy $policyname ..." + Import-SpbmStoragePolicy -FilePath $Path\$file -Name $policyName + } + } +} \ No newline at end of file From cdfd510dd9cfb7e61f3cf23f7fc13e3fbfd55585 Mon Sep 17 00:00:00 2001 From: William Lam Date: Tue, 21 Nov 2017 09:37:27 -0800 Subject: [PATCH 20/28] Whoops, missed folder for module --- Modules/vCenterManualMigration.psm1 | 475 ---------------------------- 1 file changed, 475 deletions(-) delete mode 100644 Modules/vCenterManualMigration.psm1 diff --git a/Modules/vCenterManualMigration.psm1 b/Modules/vCenterManualMigration.psm1 deleted file mode 100644 index a7750b9..0000000 --- a/Modules/vCenterManualMigration.psm1 +++ /dev/null @@ -1,475 +0,0 @@ -Function Export-DRSRules { -<# - .NOTES - =========================================================================== - Created by: William Lam - Date: 11/21/2017 - Blog: https://www.virtuallyghetto.com - Twitter: @lamw - =========================================================================== - - .SYNOPSIS - Export DRS Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .DESCRIPTION - Export DRS Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .EXAMPLE - Export-DRSRules -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster -#> - param( - [Parameter(Mandatory=$false)][String]$Path, - [Parameter(Mandatory=$true)][String]$Cluster - ) - - $rules = Get-Cluster -Name $Cluster | Get-DrsRule - - $results = @() - foreach ($rule in $rules) { - $vmNames = @() - $vmIds = $rule.VMIds - - # Reconstruct MoRef ID to VM Object to get Name - foreach ($vmId in $vmIds) { - $vm = New-Object VMware.Vim.ManagedObjectReference - $vm.Type = "VirtualMachine" - $vm.Value = ($vmId -replace "VirtualMachine-","") - $vmView = Get-View $vm - $vmNames += $vmView.name - } - - $rulesObject = [pscustomobject] @{ - Name = $rule.ExtensionData.Name; - Type = $rule.Type; #VMAffinity = 1, VMAntiAffinity = 0 - Enabled = $rule.Enabled; - Mandatory = $rule.ExtensionData.Mandatory - VM = $vmNames - } - $results+=$rulesObject - } - if($Path) { - $fullPath = $Path + "\DRSRules.json" - Write-Host -ForegroundColor Green "Exporting DRS Rules to $fullpath ..." - $results | ConvertTo-Json | Out-File $fullPath - } else { - $results | ConvertTo-Json - } -} - -Function Import-DRSRules { -<# - .NOTES - =========================================================================== - Created by: William Lam - Date: 11/21/2017 - Blog: https://www.virtuallyghetto.com - Twitter: @lamw - =========================================================================== - - .SYNOPSIS - Import DRS Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .DESCRIPTION - Import DRS Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .EXAMPLE - Import-DRSRules -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster -#> - param( - [Parameter(Mandatory=$true)][String]$Path, - [Parameter(Mandatory=$true)][String]$Cluster - ) - - Get-DrsRule -Cluster $cluster | Remove-DrsRule -Confirm:$false | Out-Null - - $DRSRulesFilename = "/DRSRules.json" - $fullPath = $Path + $DRSRulesFilename - $json = Get-Content -Raw $fullPath | ConvertFrom-Json - - foreach ($line in $json) { - $vmArr = @() - $vmNames = $line.vm - foreach ($vmName in $vmNames) { - $vmView = Get-VM -Name $vmName - $vmArr+=$vmView - } - New-DrsRule -Name $line.name -Enabled $line.Enabled -Cluster (Get-Cluster -Name $Cluster) -KeepTogether $line.Type -VM $vmArr - } -} - -Function Export-DRSClusterGroup { -<# - .NOTES - =========================================================================== - Created by: William Lam - Date: 11/21/2017 - Blog: https://www.virtuallyghetto.com - Twitter: @lamw - =========================================================================== - - .SYNOPSIS - Export DRS Cluster Group Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .DESCRIPTION - Export DRS Cluster Group Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .EXAMPLE - Export-DRSClusterGroup -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster -#> - param( - [Parameter(Mandatory=$false)][String]$Path, - [Parameter(Mandatory=$true)][String]$Cluster - ) - - $rules = Get-Cluster -Name $Cluster | Get-DrsClusterGroup - - $results = @() - foreach ($rule in $rules) { - $rulesObject = [pscustomobject] @{ - Name = $rule.ExtensionData.Name; - Type = $rule.GroupType; #VMType = 1, HostType = 0 - Member = $rule.Member - } - $results+=$rulesObject - } - if($Path) { - $fullPath = $Path + "\DRSClusterGroupRules.json" - Write-Host -ForegroundColor Green "Exporting DRS Cluster Group Rules to $fullpath ..." - $results | ConvertTo-Json | Out-File $fullPath - } else { - $results | ConvertTo-Json - } -} - -Function Import-DRSClusterClusterGroup { -<# - .NOTES - =========================================================================== - Created by: William Lam - Date: 11/21/2017 - Blog: https://www.virtuallyghetto.com - Twitter: @lamw - =========================================================================== - - .SYNOPSIS - Import DRS Cluster Group Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .DESCRIPTION - Import DRS Cluster Group Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .EXAMPLE - Import-DRSClusterClusterGroup -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster -#> - param( - [Parameter(Mandatory=$true)][String]$Path, - [Parameter(Mandatory=$true)][String]$Cluster - ) - - $DRSClusterGroupRulesFilename = "\DRSClusterGroupRules.json" - $fullPath = $Path + $DRSClusterGroupRulesFilename - $json = Get-Content -Raw $fullPath | ConvertFrom-Json - - foreach ($line in $json) { - $memberArr = @() - $members = $line.member - - # VMHost Group - if($line.Type -eq 0) { - foreach ($member in $members) { - $memberView = Get-VMhost -Name $member - $memberArr+=$memberView - } - New-DrsClusterGroup -Name $line.name -Cluster (Get-Cluster -Name $Cluster) -VMhost $memberArr - # VM Group - } else { - foreach ($member in $members) { - $memberView = Get-VM -Name $member - $memberArr+=$memberView - } - New-DrsClusterGroup -Name $line.name -Cluster (Get-Cluster -Name $Cluster) -VM $memberArr - } - } -} - -Function Export-Tag { -<# - .NOTES - =========================================================================== - Created by: William Lam - Date: 11/21/2017 - Blog: https://www.virtuallyghetto.com - Twitter: @lamw - =========================================================================== - - .SYNOPSIS - Export vSphere Tags and VM Assocations to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .DESCRIPTION - Export vSphere Tags and VM Assocations to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .EXAMPLE - Export-Tag -Path C:\Users\primp\Desktop\VMworld2017 -#> - param( - [Parameter(Mandatory=$false)][String]$Path - ) - - # Export Tag Categories - $tagCatagorys = Get-TagCategory - - $tagCatresults = @() - foreach ($tagCategory in $tagCatagorys) { - $tagCatObj = [pscustomobject] @{ - Name = $tagCategory.Name; - Cardinality = $tagCategory.Cardinality; - Description = $tagCategory.Description; - Type = $tagCategory.EntityType - } - $tagCatresults+=$tagCatObj - } - if($Path) { - $fullPath = $Path + "\AllTagCategory.json" - Write-Host -ForegroundColor Green "Exporting vSphere Tag Category to $fullpath ..." - $tagCatresults | ConvertTo-Json | Out-File $fullPath - } else { - $tagCatresults | ConvertTo-Json - } - - # Export Tags - $tags = Get-Tag - - $tagResults = @() - foreach ($tag in $tags) { - $tagObj = [pscustomobject] @{ - Name = $tag.Name; - Description = $tag.Description; - Category = $tag.Category.Name - } - $tagResults+=$tagObj - } - if($Path) { - $fullPath = $Path + "\AllTag.json" - Write-Host -ForegroundColor Green "Exporting vSphere Tag to $fullpath ..." - $tagResults | ConvertTo-Json | Out-File $fullPath - } else { - $tagResults | ConvertTo-Json - } - - # Export VM to Tag Mappings - $vms = Get-VM - - $vmResults = @() - foreach ($vm in $vms) { - $tagAssignments = $vm | Get-TagAssignment - $tags = @() - foreach ($tagAssignment in $tagAssignments) { - $tag = $tagAssignment.Tag - $tagName = $tag -split "/" - $tags+=$tagName - } - $vmObj = [pscustomobject] @{ - Name = $vm.name; - Tag = $tags - } - $vmResults+=$vmObj - } - if($Path) { - $fullPath = $Path + "\AllTagAssocations.json" - Write-Host -ForegroundColor Green "Exporting VM to vSphere Tag Assignment to $fullpath ..." - $vmResults | ConvertTo-Json | Out-File $fullPath - } else { - $vmResults | ConvertTo-Json - } -} - -Function Import-Tag { -<# - .NOTES - =========================================================================== - Created by: William Lam - Date: 11/21/2017 - Blog: https://www.virtuallyghetto.com - Twitter: @lamw - =========================================================================== - - .SYNOPSIS - Import vSphere Tags and VM Assocations from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .DESCRIPTION - Import vSphere Tags and VM Assocations from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .EXAMPLE - Import-Tag -Path C:\Users\primp\Desktop\VMworld2017 -#> - param( - [Parameter(Mandatory=$true)][String]$Path - ) - - $tagCatFilename = "\AllTagCategory.json" - $fullPath = $Path + $tagCatFilename - $tagCategoryJson = Get-Content -Raw $fullPath | ConvertFrom-Json - - $tagFilename = "\AllTag.json" - $fullPath = $Path + $tagFilename - $tagJson = Get-Content -Raw $fullPath | ConvertFrom-Json - - $vmTagFilename = "\AllTagAssocations.json" - $fullPath = $Path + $vmTagFilename - $vmTagJson = Get-Content -Raw $fullPath | ConvertFrom-Json - - # Re-Create Tag Category - foreach ($category in $tagCategoryJson) { - if($category.Cardinality -eq 0) { - $cardinality = "Single" - } else { - $cardinality = "Multiple" - } - New-TagCategory -Name $category.Name -Cardinality $cardinality -Description $category.Description -EntityType $category.Type - } - - # Re-Create Tags - foreach ($tag in $tagJson) { - New-Tag -Name $tag.Name -Description $tag.Description -Category (Get-TagCategory -Name $tag.Category) - } - - # Re-Create VM to Tag Mappings - foreach ($vmTag in $vmTagJson) { - $vm = Get-VM -Name $vmTag.name - $tags = $vmTag.Tag - foreach ($tag in $tags) { - New-TagAssignment -Entity $vm -Tag (Get-Tag -Name $tag) - } - } -} - -Function Export-VMFolder { -<# - .NOTES - =========================================================================== - Created by: William Lam - Date: 11/21/2017 - Blog: https://www.virtuallyghetto.com - Twitter: @lamw - =========================================================================== - - .SYNOPSIS - Export vSphere Folder to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .DESCRIPTION - Export vSphere Folder to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .EXAMPLE - Export-VMFolder -Path C:\Users\primp\Desktop\VMworld2017 -#> - param( - [Parameter(Mandatory=$false)][String]$Path - ) - $vms = Get-VM - - $vmFolderResults = @() - foreach ($vm in $vms) { - $vmFolderObj = [pscustomobject] @{ - Name = $vm.name; - Folder = $vm.Folder.Name; - } - $vmFolderResults+=$vmFolderObj - } - if($Path) { - $fullPath = $Path + "\AllVMFolder.json" - Write-Host -ForegroundColor Green "Exporting VM Folders to $fullpath ..." - $vmFolderResults | ConvertTo-Json | Out-File $fullPath - } else { - $vmFolderResults | ConvertTo-Json - } -} - -Function Import-VMFolder { -<# - .NOTES - =========================================================================== - Created by: William Lam - Date: 11/21/2017 - Blog: https://www.virtuallyghetto.com - Twitter: @lamw - =========================================================================== - - .SYNOPSIS - Import vSphere Folder from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .DESCRIPTION - Import vSphere Folder from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .EXAMPLE - Import-VMFolder -Path C:\Users\primp\Desktop\VMworld2017 -#> - param( - [Parameter(Mandatory=$true)][String]$Path - ) - - $vmFolderFilename = "\AllVMFolder.json" - $fullPath = $Path + $vmFolderFilename - $vmFolderJson = Get-Content -Raw $fullPath | ConvertFrom-Json - - # Root vm Folder - $rootVMFolder = Get-Folder -Type VM -Name vm - - $folders = $vmFolderJson | Select Folder | Sort-Object -Property Folder -Unique - foreach ($folder in $folders) { - $rootVMFolder | New-Folder -Name $folder.folder - } - - foreach ($vmFolder in $vmFolderJson) { - $vm = Get-VM -Name $vmFolder.Name - $folder = Get-Folder -Name $vmFolder.Folder - Move-VM -VM $vm -Destination $folder - } -} - -Function Export-VMStoragePolicy { -<# - .NOTES - =========================================================================== - Created by: William Lam - Date: 11/21/2017 - Blog: https://www.virtuallyghetto.com - Twitter: @lamw - =========================================================================== - - .SYNOPSIS - Export VM Storage Policies to JSON file - .DESCRIPTION - Export VM Storage Policies to JSON file - .EXAMPLE - Export-VMStoragePolicy -Path C:\Users\primp\Desktop\VMworld2017 -#> - param( - [Parameter(Mandatory=$false)][String]$Path - ) - - foreach ($policy in Get-SpbmStoragePolicy) { - $policyName = $policy.Name - if($Path) { - Write-Host -ForegroundColor Green "Exporting Policy $policyName to $Path\$policyName.xml ..." - $policy | Export-SpbmStoragePolicy -FilePath $Path\$policyName.xml -Force | Out-Null - } else { - $policy - } - } -} - -Function Import-VMStoragePolicy { -<# - .NOTES - =========================================================================== - Created by: William Lam - Date: 11/21/2017 - Blog: https://www.virtuallyghetto.com - Twitter: @lamw - =========================================================================== - - .SYNOPSIS - Import VM Storage Policies from JSON file - .DESCRIPTION - Import VM Storage Policies from JSON file - .EXAMPLE - Import-VMStoragePolicy -Path C:\Users\primp\Desktop\VMworld2017 -#> - param( - [Parameter(Mandatory=$false)][String]$Path - ) - - foreach ($file in Get-ChildItem -Path $Path -Filter *.xml) { - $policyName = $file.name - $policyName = $policyName.replace(".xml","") - if(Get-SpbmStoragePolicy -Name $policyName -ErrorAction SilentlyContinue) { - Continue - } else { - Write-Host "Importing Policy $policyname ..." - Import-SpbmStoragePolicy -FilePath $Path\$file -Name $policyName - } - } -} \ No newline at end of file From d104a293934819d792ce2ab1af449c5af51ce236 Mon Sep 17 00:00:00 2001 From: William Lam Date: Tue, 21 Nov 2017 09:38:24 -0800 Subject: [PATCH 21/28] Might be useful if I actually added directory --- .../vCenterManualMigration.psm1 | 475 ++++++++++++++++++ 1 file changed, 475 insertions(+) create mode 100644 Modules/vCenterManualMigration/vCenterManualMigration.psm1 diff --git a/Modules/vCenterManualMigration/vCenterManualMigration.psm1 b/Modules/vCenterManualMigration/vCenterManualMigration.psm1 new file mode 100644 index 0000000..a7750b9 --- /dev/null +++ b/Modules/vCenterManualMigration/vCenterManualMigration.psm1 @@ -0,0 +1,475 @@ +Function Export-DRSRules { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Export DRS Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Export DRS Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Export-DRSRules -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster +#> + param( + [Parameter(Mandatory=$false)][String]$Path, + [Parameter(Mandatory=$true)][String]$Cluster + ) + + $rules = Get-Cluster -Name $Cluster | Get-DrsRule + + $results = @() + foreach ($rule in $rules) { + $vmNames = @() + $vmIds = $rule.VMIds + + # Reconstruct MoRef ID to VM Object to get Name + foreach ($vmId in $vmIds) { + $vm = New-Object VMware.Vim.ManagedObjectReference + $vm.Type = "VirtualMachine" + $vm.Value = ($vmId -replace "VirtualMachine-","") + $vmView = Get-View $vm + $vmNames += $vmView.name + } + + $rulesObject = [pscustomobject] @{ + Name = $rule.ExtensionData.Name; + Type = $rule.Type; #VMAffinity = 1, VMAntiAffinity = 0 + Enabled = $rule.Enabled; + Mandatory = $rule.ExtensionData.Mandatory + VM = $vmNames + } + $results+=$rulesObject + } + if($Path) { + $fullPath = $Path + "\DRSRules.json" + Write-Host -ForegroundColor Green "Exporting DRS Rules to $fullpath ..." + $results | ConvertTo-Json | Out-File $fullPath + } else { + $results | ConvertTo-Json + } +} + +Function Import-DRSRules { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Import DRS Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Import DRS Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Import-DRSRules -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster +#> + param( + [Parameter(Mandatory=$true)][String]$Path, + [Parameter(Mandatory=$true)][String]$Cluster + ) + + Get-DrsRule -Cluster $cluster | Remove-DrsRule -Confirm:$false | Out-Null + + $DRSRulesFilename = "/DRSRules.json" + $fullPath = $Path + $DRSRulesFilename + $json = Get-Content -Raw $fullPath | ConvertFrom-Json + + foreach ($line in $json) { + $vmArr = @() + $vmNames = $line.vm + foreach ($vmName in $vmNames) { + $vmView = Get-VM -Name $vmName + $vmArr+=$vmView + } + New-DrsRule -Name $line.name -Enabled $line.Enabled -Cluster (Get-Cluster -Name $Cluster) -KeepTogether $line.Type -VM $vmArr + } +} + +Function Export-DRSClusterGroup { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Export DRS Cluster Group Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Export DRS Cluster Group Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Export-DRSClusterGroup -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster +#> + param( + [Parameter(Mandatory=$false)][String]$Path, + [Parameter(Mandatory=$true)][String]$Cluster + ) + + $rules = Get-Cluster -Name $Cluster | Get-DrsClusterGroup + + $results = @() + foreach ($rule in $rules) { + $rulesObject = [pscustomobject] @{ + Name = $rule.ExtensionData.Name; + Type = $rule.GroupType; #VMType = 1, HostType = 0 + Member = $rule.Member + } + $results+=$rulesObject + } + if($Path) { + $fullPath = $Path + "\DRSClusterGroupRules.json" + Write-Host -ForegroundColor Green "Exporting DRS Cluster Group Rules to $fullpath ..." + $results | ConvertTo-Json | Out-File $fullPath + } else { + $results | ConvertTo-Json + } +} + +Function Import-DRSClusterClusterGroup { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Import DRS Cluster Group Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Import DRS Cluster Group Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Import-DRSClusterClusterGroup -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster +#> + param( + [Parameter(Mandatory=$true)][String]$Path, + [Parameter(Mandatory=$true)][String]$Cluster + ) + + $DRSClusterGroupRulesFilename = "\DRSClusterGroupRules.json" + $fullPath = $Path + $DRSClusterGroupRulesFilename + $json = Get-Content -Raw $fullPath | ConvertFrom-Json + + foreach ($line in $json) { + $memberArr = @() + $members = $line.member + + # VMHost Group + if($line.Type -eq 0) { + foreach ($member in $members) { + $memberView = Get-VMhost -Name $member + $memberArr+=$memberView + } + New-DrsClusterGroup -Name $line.name -Cluster (Get-Cluster -Name $Cluster) -VMhost $memberArr + # VM Group + } else { + foreach ($member in $members) { + $memberView = Get-VM -Name $member + $memberArr+=$memberView + } + New-DrsClusterGroup -Name $line.name -Cluster (Get-Cluster -Name $Cluster) -VM $memberArr + } + } +} + +Function Export-Tag { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Export vSphere Tags and VM Assocations to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Export vSphere Tags and VM Assocations to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Export-Tag -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$false)][String]$Path + ) + + # Export Tag Categories + $tagCatagorys = Get-TagCategory + + $tagCatresults = @() + foreach ($tagCategory in $tagCatagorys) { + $tagCatObj = [pscustomobject] @{ + Name = $tagCategory.Name; + Cardinality = $tagCategory.Cardinality; + Description = $tagCategory.Description; + Type = $tagCategory.EntityType + } + $tagCatresults+=$tagCatObj + } + if($Path) { + $fullPath = $Path + "\AllTagCategory.json" + Write-Host -ForegroundColor Green "Exporting vSphere Tag Category to $fullpath ..." + $tagCatresults | ConvertTo-Json | Out-File $fullPath + } else { + $tagCatresults | ConvertTo-Json + } + + # Export Tags + $tags = Get-Tag + + $tagResults = @() + foreach ($tag in $tags) { + $tagObj = [pscustomobject] @{ + Name = $tag.Name; + Description = $tag.Description; + Category = $tag.Category.Name + } + $tagResults+=$tagObj + } + if($Path) { + $fullPath = $Path + "\AllTag.json" + Write-Host -ForegroundColor Green "Exporting vSphere Tag to $fullpath ..." + $tagResults | ConvertTo-Json | Out-File $fullPath + } else { + $tagResults | ConvertTo-Json + } + + # Export VM to Tag Mappings + $vms = Get-VM + + $vmResults = @() + foreach ($vm in $vms) { + $tagAssignments = $vm | Get-TagAssignment + $tags = @() + foreach ($tagAssignment in $tagAssignments) { + $tag = $tagAssignment.Tag + $tagName = $tag -split "/" + $tags+=$tagName + } + $vmObj = [pscustomobject] @{ + Name = $vm.name; + Tag = $tags + } + $vmResults+=$vmObj + } + if($Path) { + $fullPath = $Path + "\AllTagAssocations.json" + Write-Host -ForegroundColor Green "Exporting VM to vSphere Tag Assignment to $fullpath ..." + $vmResults | ConvertTo-Json | Out-File $fullPath + } else { + $vmResults | ConvertTo-Json + } +} + +Function Import-Tag { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Import vSphere Tags and VM Assocations from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Import vSphere Tags and VM Assocations from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Import-Tag -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$true)][String]$Path + ) + + $tagCatFilename = "\AllTagCategory.json" + $fullPath = $Path + $tagCatFilename + $tagCategoryJson = Get-Content -Raw $fullPath | ConvertFrom-Json + + $tagFilename = "\AllTag.json" + $fullPath = $Path + $tagFilename + $tagJson = Get-Content -Raw $fullPath | ConvertFrom-Json + + $vmTagFilename = "\AllTagAssocations.json" + $fullPath = $Path + $vmTagFilename + $vmTagJson = Get-Content -Raw $fullPath | ConvertFrom-Json + + # Re-Create Tag Category + foreach ($category in $tagCategoryJson) { + if($category.Cardinality -eq 0) { + $cardinality = "Single" + } else { + $cardinality = "Multiple" + } + New-TagCategory -Name $category.Name -Cardinality $cardinality -Description $category.Description -EntityType $category.Type + } + + # Re-Create Tags + foreach ($tag in $tagJson) { + New-Tag -Name $tag.Name -Description $tag.Description -Category (Get-TagCategory -Name $tag.Category) + } + + # Re-Create VM to Tag Mappings + foreach ($vmTag in $vmTagJson) { + $vm = Get-VM -Name $vmTag.name + $tags = $vmTag.Tag + foreach ($tag in $tags) { + New-TagAssignment -Entity $vm -Tag (Get-Tag -Name $tag) + } + } +} + +Function Export-VMFolder { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Export vSphere Folder to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Export vSphere Folder to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Export-VMFolder -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$false)][String]$Path + ) + $vms = Get-VM + + $vmFolderResults = @() + foreach ($vm in $vms) { + $vmFolderObj = [pscustomobject] @{ + Name = $vm.name; + Folder = $vm.Folder.Name; + } + $vmFolderResults+=$vmFolderObj + } + if($Path) { + $fullPath = $Path + "\AllVMFolder.json" + Write-Host -ForegroundColor Green "Exporting VM Folders to $fullpath ..." + $vmFolderResults | ConvertTo-Json | Out-File $fullPath + } else { + $vmFolderResults | ConvertTo-Json + } +} + +Function Import-VMFolder { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Import vSphere Folder from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Import vSphere Folder from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Import-VMFolder -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$true)][String]$Path + ) + + $vmFolderFilename = "\AllVMFolder.json" + $fullPath = $Path + $vmFolderFilename + $vmFolderJson = Get-Content -Raw $fullPath | ConvertFrom-Json + + # Root vm Folder + $rootVMFolder = Get-Folder -Type VM -Name vm + + $folders = $vmFolderJson | Select Folder | Sort-Object -Property Folder -Unique + foreach ($folder in $folders) { + $rootVMFolder | New-Folder -Name $folder.folder + } + + foreach ($vmFolder in $vmFolderJson) { + $vm = Get-VM -Name $vmFolder.Name + $folder = Get-Folder -Name $vmFolder.Folder + Move-VM -VM $vm -Destination $folder + } +} + +Function Export-VMStoragePolicy { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Export VM Storage Policies to JSON file + .DESCRIPTION + Export VM Storage Policies to JSON file + .EXAMPLE + Export-VMStoragePolicy -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$false)][String]$Path + ) + + foreach ($policy in Get-SpbmStoragePolicy) { + $policyName = $policy.Name + if($Path) { + Write-Host -ForegroundColor Green "Exporting Policy $policyName to $Path\$policyName.xml ..." + $policy | Export-SpbmStoragePolicy -FilePath $Path\$policyName.xml -Force | Out-Null + } else { + $policy + } + } +} + +Function Import-VMStoragePolicy { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Import VM Storage Policies from JSON file + .DESCRIPTION + Import VM Storage Policies from JSON file + .EXAMPLE + Import-VMStoragePolicy -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$false)][String]$Path + ) + + foreach ($file in Get-ChildItem -Path $Path -Filter *.xml) { + $policyName = $file.name + $policyName = $policyName.replace(".xml","") + if(Get-SpbmStoragePolicy -Name $policyName -ErrorAction SilentlyContinue) { + Continue + } else { + Write-Host "Importing Policy $policyname ..." + Import-SpbmStoragePolicy -FilePath $Path\$file -Name $policyName + } + } +} \ No newline at end of file From d6861d38fb4e8eac4d2168220d0e5f8047e62f4b Mon Sep 17 00:00:00 2001 From: alanrenouf Date: Tue, 28 Nov 2017 22:48:08 -0800 Subject: [PATCH 22/28] New VMware Cloud on AWS functions module --- Modules/VMware.VMC/VMware.VMC.psd1 | Bin 0 -> 7976 bytes Modules/VMware.VMC/VMware.VMC.psm1 | 323 +++++++++++++++++++++++++++++ 2 files changed, 323 insertions(+) create mode 100755 Modules/VMware.VMC/VMware.VMC.psd1 create mode 100644 Modules/VMware.VMC/VMware.VMC.psm1 diff --git a/Modules/VMware.VMC/VMware.VMC.psd1 b/Modules/VMware.VMC/VMware.VMC.psd1 new file mode 100755 index 0000000000000000000000000000000000000000..74256ef01bb8a2e4a146aa91e45b35b01949b08f GIT binary patch literal 7976 zcmeI1T~Av_5Qg`fUvVTZOsa;IG)tQXdha$WT=b;}i!f6=j?kse}C=A1~?xta;C&zj} ziEqkut#GK7m!h7Cax>m_LM!q#zR&c0q`!%1X8P`n$5Hqce$h8;M&f%R?%nVte9*p$ zS5I%wmT)@PdN^(Ab1&QvkMw^l{5)T^CZ2!k+K}vro^~9Dag^sQlhKI$#ki^S@>P+_&*dyU5lGS@~I{Plr^7ZUJK8{+hANxzQ?lNPg?U>QvN6&cXj_zDDUg)fi(SCobL)d*N=477gaw# zhh`wkhjB&HPFuLx-Tde}3#^5l))2KN6A@R)KT=F2{z;#sD5>r9A=36&+BN6!O1qtD zwdp_iynNTO_9JReBprExY+zo`dbFQ%!y^5&ca@LHy&*l`5r_M-1aVtb@<}0Wo$5ob za12BinFIfrC}-d$o2BU3j_*>edz2)rAop?fsGjiK`>uAukMXRr_@0Zid6;LcJhIFF zwP;6^aZkK1Bi4QC5bs5vaug;FzKmYbmA1)5C!#Co*CKSZmV5~&i~V+ZrzlJ|dl^>_ zWnFSY5%n{Xu9~&*E>hz`m!c^YqfJ<`vmrur=$<$n#;fJpY2w+OcOF!7PV&;+cB`Q# z8m)HS6!H23O+24-Ot{R#UswBIPmX3Q+*BGoj%Y*M*olm=8D6O}9O!CCZ!Fhb>g^=F zzp)2xYQ@1-O(iyod-p*+n|ee&z=J<%HzFCo^qz&h1Vxi47OFPnlK0|5mMU~tu4oo# zR2*t2p0O>undBSje_gsSqfa(W6m|{lh>}|S-$(K zXm_F?GqDmW{{`YQf>lvhxN-E%Zm8S1gK6C)sX*&sGa2jSyYF2id0B>if0&LLlWHOJd5DW{X?y?Nz9^y&8t-uhZPGERgz zjhcy<^)IG<&RkBHtl!g0t1&&vv$ud6?RZDujMnkwT}bMWJFFYY} zVD(&w&05c`zOB5}k&Vd(bo%u4*7x78qWCN~6&HHhoaZWtUdRiq4p|LG@>3x!*I@jE zQ_!B~OPkrKHO*(msjeHga&=96)oW~em*XgRLbt`R6D#IGGo{N~-=BVR80T)QmVHUe z8KK*Sy_wGZ-m7U@PhYxM$){O*18OlA!p?>4!8`;?>xV$g`SiA)7L8vlm2t-rU5>KFP>a~ z99Km~hNd64y22?AxrUsQ=AWjM3fI4XV~54O@T}In())_fdd8}!@)>fs?UzSgJy*~x zELvI4mMONId9d^IDEnBQ>?qDU=G(hhSei9&HKe+hs97vPq6y@_L>X&;*kfQEDf&+@;RHii7+~obbEIu5kES*xhV$Ej0Py W|Bjy+sms{OWGU0<+WD;2YvEtFqc#)( literal 0 HcmV?d00001 diff --git a/Modules/VMware.VMC/VMware.VMC.psm1 b/Modules/VMware.VMC/VMware.VMC.psm1 new file mode 100644 index 0000000..674668b --- /dev/null +++ b/Modules/VMware.VMC/VMware.VMC.psm1 @@ -0,0 +1,323 @@ +Function Get-VMCCommand { +<# + .NOTES + =========================================================================== + Created by: VMware + Date: 11/17/2017 + Organization: VMware + Blog: http://vmware.com/go/powercli + Twitter: @powercli + =========================================================================== + + .SYNOPSIS + Returns all cmdlets for VMware Cloud on AWS + .DESCRIPTION + This cmdlet will allow you to return all cmdlets included in the VMC module + .EXAMPLE + Get-VMCCommand + .EXAMPLE + Get-Command -Module VMware.VMC + .NOTES + You can either use this cmdlet or the Get-Command cmdlet as seen in Example 2 +#> + Get-command -Module VMware.VimAutomation.Vmc + Get-Command -Module VMware.VMC + +} +Function Connect-VMCVIServer { +<# + .NOTES + =========================================================================== + Created by: VMware + Date: 11/17/2017 + Organization: VMware + Blog: http://vmware.com/go/powercli + Twitter: @powercli + =========================================================================== + + .SYNOPSIS + Cmdlet to connect to your VMC vCenter Server + .DESCRIPTION + This will connect you to both the VMC ViServer as well as the CiSServer at the same time. + .EXAMPLE + Connect-VMCVIServer -Server -User -Password + .NOTES + Easiest way is to pipe through your credentials from Get-VMCSDDCDefaultCredential +#> + Param ( + [Parameter(Mandatory=$true)]$Org, + [Parameter(Mandatory=$true)]$Sddc, + [switch]$Autologin + ) + + If (-Not $global:DefaultVMCServers) { Write-error "No VMC Connection found, please use the Connect-VMC to connect" } Else { + $creds = Get-VMCSDDCDefaultCredential -Org $Org -Sddc $Sddc + Write-Host "Connecting to VMC vCenter Server" $creds.vc_public_ip + Connect-VIServer -Server $creds.vc_public_ip -User $creds.cloud_username -Password $creds.cloud_password | Add-Member -MemberType Noteproperty -Name Location -Value "VMC" + Write-Host "Connecting to VMC CIS Endpoint" $creds.vc_public_ip + Connect-CisServer -Server $creds.vc_public_ip -User $creds.cloud_username -Password $creds.cloud_password | Add-Member -MemberType Noteproperty -Name Location -Value "VMC" + } +} +Function Get-VMCOrg { +<# + .NOTES + =========================================================================== + Created by: VMware + Date: 11/17/2017 + Organization: VMware + Blog: http://vmware.com/go/powercli + Twitter: @powercli + =========================================================================== + + .SYNOPSIS + Return the Orgs that you are a part of + .DESCRIPTION + Depending on what you've purchased, you may be a part of one or more VMC Orgs. This will return your orgs + .EXAMPLE + Get-VMCOrg + .EXAMPLE + Get-VMCOrg -Name + .NOTES + Return all the info about the orgs you are a part of +#> + Param ( + [Parameter(Mandatory=$false)]$Name + ) + + If (-Not $global:DefaultVMCServers) { Write-error "No VMC Connection found, please use Connect-VMC to connect" } Else { + $orgService = Get-VMCService com.vmware.vmc.orgs + if ($PSBoundParameters.ContainsKey("Name")){ + $orgs = $orgService.list() | Where {$_.display_name -match $Name} + } Else { + $orgs = $orgService.list() + } + $Orgs | Select display_name, name, user_name, created, id + } +} +Function Get-VMCSDDC { +<# + .NOTES + =========================================================================== + Created by: VMware + Date: 11/17/2017 + Organization: VMware + Blog: http://vmware.com/go/powercli + Twitter: @powercli + =========================================================================== + + .SYNOPSIS + Returns all of the SDDCs you are associated to + .DESCRIPTION + Returns all of the SDDCs ayou are associated to + .EXAMPLE + Get-VMCSDDC -Org + .EXAMPLE + Get-VMCSDDC -Name -Org +#> + Param ( + [Parameter(Mandatory=$True)]$Org, + [Parameter(Mandatory=$false)]$Name + ) + + If (-Not $global:DefaultVMCServers) { Write-error "No VMC Connection found, please use the Connect-VMC to connect" } Else { + if ($PSBoundParameters.ContainsKey("Org")){ + $orgs = Get-VMCOrg -Name $Org + } else { + $orgs = Get-VMCOrg + } + + foreach ($org in $orgs) { + $orgID = $org.ID + $sddcService = Get-VMCService com.vmware.vmc.orgs.sddcs + if ($PSBoundParameters.ContainsKey("Name")){ + $sddcService.list($OrgID) | Where {$_.name -match $Name} + } Else { + $sddcService.list($OrgID) + } + } + } +} +Function Get-VMCTask { +<# + .NOTES + =========================================================================== + Created by: VMware + Date: 11/17/2017 + Organization: VMware + Blog: http://vmware.com/go/powercli + Twitter: @powercli + =========================================================================== + + .SYNOPSIS + Returns all of the VMC Tasks + .DESCRIPTION + Returns all of the VMC Tasks that have either occurred or are in process + .EXAMPLE + Get-VMCTask +#> + Param ( + [Parameter(Mandatory=$True)]$Org + ) + + If (-Not $global:DefaultVMCServers) { Write-error "No VMC Connection found, please use the Connect-VMC to connect" } Else { + if ($PSBoundParameters.ContainsKey("Org")){ + $orgs = Get-VMCOrg -Name $Org + } else { + $orgs = Get-VMCOrg + } + + foreach ($org in $orgs) { + $orgID = $org.ID + $taskService = Get-VMCService com.vmware.vmc.orgs.tasks + $taskService.list($OrgID) | Select * -ExcludeProperty Help + } + } +} +Function Get-VMCSDDCDefaultCredential { +<# + .NOTES + =========================================================================== + Created by: VMware + Date: 11/17/2017 + Organization: VMware + Blog: http://vmware.com/go/powercli + Twitter: @powercli + =========================================================================== + + .SYNOPSIS + Returns the default credential for the SDDC + .DESCRIPTION + Returns the default credential for the sddc + .EXAMPLE + Get-VMCSDDCDefaultCredential -Org + .EXAMPLE + Get-VMCSDDCDefaultCredential -Sddc -Org +#> + Param ( + [Parameter(Mandatory=$true)]$Org, + [Parameter(Mandatory=$false)]$Sddc + ) + + If (-Not $global:DefaultVMCServers) { Write-error "No VMC Connection found, please use the Connect-VMC to connect" } Else { + if ($PSBoundParameters.ContainsKey("Sddc")){ + $sddcs = Get-VMCSDDC -Name $Sddc -Org $Org + } else { + $sddcs = Get-VMCSDDC -Org $Org + } + + foreach ($sddc in $sddcs) { + $sddc.resource_config | Select-object vc_url, vc_management_ip, vc_public_ip, cloud_username, cloud_password + } + } +} +Function Get-VMCSDDCPublicIP { +<# + .NOTES + =========================================================================== + Created by: VMware + Date: 11/17/2017 + Organization: VMware + Blog: http://vmware.com/go/powercli + Twitter: @powercli + =========================================================================== + + .SYNOPSIS + Returns your Public IPs + .DESCRIPTION + Returns your Public IPs + .EXAMPLE + Get-VMCSDDCPublicIP -Org + .EXAMPLE + Get-VMCSDDCPublicIP -Sddc -Org + .NOTES + Return your Public IPs that you have assigned to your account +#> + Param ( + [Parameter(Mandatory=$true)]$Org, + [Parameter(Mandatory=$false)]$Sddc + ) + + If (-Not $global:DefaultVMCServers) { Write-error "No VMC Connection found, please use the Connect-VMC to connect" } Else { + if ($PSBoundParameters.ContainsKey("Sddc")){ + $sddcs = Get-VMCSDDC -Name $Sddc -Org $Org + } else { + $sddcs = Get-VMCSDDC -Org $Org + } + + foreach ($sddc in $sddcs) { + $sddc.resource_config.Public_ip_pool + } + } +} +Function Get-VMCVMHost { + Param ( + [Parameter(Mandatory=$false)]$Sddc, + [Parameter(Mandatory=$true)]$Org + ) + + If (-Not $global:DefaultVMCServers) { Write-error "No VMC Connection found, please use the Connect-VMC to connect" } Else { + if ($PSBoundParameters.ContainsKey("Sddc")){ + $sddcs = Get-VMCSDDC -Name $Sddc -Org $Org + } else { + $sddcs = Get-VMCSDDC -Org $Org + } + + $results = @() + foreach ($sddc in $sddcs) { + foreach ($vmhost in $sddc.resource_config.esx_hosts) { + $tmp = [pscustomobject] @{ + esx_id = $vmhost.esx_id; + name = $vmhost.name; + hostname = $vmhost.hostname; + esx_state = $vmhost.esx_state; + sddc_id = $sddc.id; + org_id = $sddc.org_id; + } + $results += $tmp + } + $results + } + } +} +Function Get-VMCSDDCVersion { +<# + .NOTES + =========================================================================== + Created by: VMware + Date: 11/17/2017 + Organization: VMware + Blog: http://vmware.com/go/powercli + Twitter: @powercli + =========================================================================== + + .SYNOPSIS + Returns SDDC Version + .DESCRIPTION + Returns Version of the SDDC + .EXAMPLE + Get-VMCSDDCVersion -Name -Org +#> + Param ( + [Parameter(Mandatory=$True)]$Org, + [Parameter(Mandatory=$false)]$Name + ) + + If (-Not $global:DefaultVMCServers) { Write-error "No VMC Connection found, please use the Connect-VMC to connect" } Else { + if ($PSBoundParameters.ContainsKey("Org")){ + $orgs = Get-VMCOrg -Name $Org + } else { + $orgs = Get-VMCOrg + } + + foreach ($org in $orgs) { + $orgID = $org.ID + $sddcService = Get-VMCService com.vmware.vmc.orgs.sddcs + if ($PSBoundParameters.ContainsKey("Name")){ + ($sddcService.list($OrgID) | Where {$_.name -match $Name}).resource_config.sddc_manifest | Select *version + } Else { + ($sddcService.list($OrgID)).resource_config.sddc_manifest | Select *version + } + } + } +} +Export-ModuleMember -Function 'Get-VMCCommand', 'Connect-VMCVIServer', 'Get-VMCOrg', 'Get-VMCSDDC', 'Get-VMCTask', 'Get-VMCSDDCDefaultCredential', 'Get-VMCSDDCPublicIP', 'Get-VMCVMHost', 'Get-VMCSDDCVersion' \ No newline at end of file From 2c2b16457cf5dcb47e99821f6a10f8bb5fec5ffc Mon Sep 17 00:00:00 2001 From: lucdekens Date: Fri, 1 Dec 2017 23:08:04 +0100 Subject: [PATCH 23/28] Add module rCisTag Module rCisTag provides CRUD functions for Tags, Tag Categories and Tag Assignments. The functions use the Cis REST API functions. This is a beta release (0.9.0), feedback welcome. --- Modules/rCisTag/MITLicense.txt | 21 + Modules/rCisTag/README.md | 15 + Modules/rCisTag/en-US/about_rCISTag.Help.txt | 26 + Modules/rCisTag/en-US/rCISTag-help.xml | 1793 ++++++++++++++++++ Modules/rCisTag/rCISTag.psd1 | Bin 0 -> 5838 bytes Modules/rCisTag/rCISTag.psm1 | 821 ++++++++ 6 files changed, 2676 insertions(+) create mode 100644 Modules/rCisTag/MITLicense.txt create mode 100644 Modules/rCisTag/README.md create mode 100644 Modules/rCisTag/en-US/about_rCISTag.Help.txt create mode 100644 Modules/rCisTag/en-US/rCISTag-help.xml create mode 100644 Modules/rCisTag/rCISTag.psd1 create mode 100644 Modules/rCisTag/rCISTag.psm1 diff --git a/Modules/rCisTag/MITLicense.txt b/Modules/rCisTag/MITLicense.txt new file mode 100644 index 0000000..b4eaf48 --- /dev/null +++ b/Modules/rCisTag/MITLicense.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) since 2015 Luc Dekens, Matt Boren + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/Modules/rCisTag/README.md b/Modules/rCisTag/README.md new file mode 100644 index 0000000..4160fdc --- /dev/null +++ b/Modules/rCisTag/README.md @@ -0,0 +1,15 @@ +# rCisTag + +A module with cmdlets to provide CRUD functions to +* Tags +* Tag Categories +* Tag Assignments + +The cmdlets use the Cis REST API + +## History + +* Author : **Luc Dekens** +* Release : + * **0.9.0** First draft + \ No newline at end of file diff --git a/Modules/rCisTag/en-US/about_rCISTag.Help.txt b/Modules/rCisTag/en-US/about_rCISTag.Help.txt new file mode 100644 index 0000000..f3b393f --- /dev/null +++ b/Modules/rCisTag/en-US/about_rCISTag.Help.txt @@ -0,0 +1,26 @@ +TOPIC + about_rCISTag + +SHORT DESCRIPTION + The rCisTag module provides CRUD functions to work with vSphere Tags + +LONG DESCRIPTION + The CisTag module provides CRUD functions to work with vSphere Tags. + The functions in the module are based on the REST API + +NOTE + The module requires PowerShell 5.0 + +TROUBLESHOOTING NOTE + + + +EXAMPLES + Get-rCisTag + +KEYWORDS + + + +SEE ALSO + Place related topics here. \ No newline at end of file diff --git a/Modules/rCisTag/en-US/rCISTag-help.xml b/Modules/rCisTag/en-US/rCISTag-help.xml new file mode 100644 index 0000000..023f48c --- /dev/null +++ b/Modules/rCisTag/en-US/rCISTag-help.xml @@ -0,0 +1,1793 @@ + + + + + Connect-rCisServer + Connect + rCisServer + + Make a connection to the CIS service on the vCenter + + + + Make a connection to the CIS service on the vCenter. Credentials need to be provided. + + + + Connect-rCisServer + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + Credential + + A PSCredential object with a user and password that is allowed to connect to the CIS service. + + PSCredential + + PSCredential + + + None + + + Fiddler + + Connects to a Fiddler instance on the station where the cmdlet is executed. Used for debugging purposes. + + + SwitchParameter + + + False + + + Proxy + + When the vCenter is located behind a proxy, specify the proxy. + + String + + String + + + None + + + Server + + The hostname of the vCenter + + String + + String + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + Connect-rCisServer + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + Fiddler + + Connects to a Fiddler instance on the station where the cmdlet is executed. Used for debugging purposes. + + + SwitchParameter + + + False + + + Password + + The user's password + + String + + String + + + None + + + Proxy + + When the vCenter is located behind a proxy, specify the proxy. + + String + + String + + + None + + + Server + + The hostname of the vCenter + + String + + String + + + None + + + User + + The user to connect to the CIS service + + String + + String + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + SwitchParameter + + SwitchParameter + + + False + + + Credential + + A PSCredential object with a user and password that is allowed to connect to the CIS service. + + PSCredential + + PSCredential + + + None + + + Fiddler + + Connects to a Fiddler instance on the station where the cmdlet is executed. Used for debugging purposes. + + SwitchParameter + + SwitchParameter + + + False + + + Password + + The user's password + + String + + String + + + None + + + Proxy + + When the vCenter is located behind a proxy, specify the proxy. + + String + + String + + + None + + + Server + + The hostname of the vCenter + + String + + String + + + None + + + User + + The user to connect to the CIS service + + String + + String + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + SwitchParameter + + SwitchParameter + + + False + + + + + + System.Management.Automation.PSCredential + + + + + + + + + + System.Object + + + + + + + + + + + + + + Example 1 + PS C:\> Connect-rCisServer -Server 'vcsa.domain.org' -User 'administrator@vsphere.local' -Password 'vSphere1!' + + Connect to the CIS service on vCenter vcsa.domain.org with user administrator@vsphere.local + + + + Example 2 + PS C:\> Connect-rCisServer -Server 'vcsa.domain.org' -Credential $cred + + Connect to the CIS service on vCenter vcsa.domain.org with the PSCredential stored in $cred + + + + + + + + Disconnect-rCisServer + Disconnect + rCisServer + + Closes the open connection to the CIS REST API + + + + Closes the open connection to the Cis REST API on the host passed on the Server parameter. + + + + Disconnect-rCisServer + + Server + + The name of the server on which the Cis REST API was opened. + + String + + String + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + SwitchParameter + + SwitchParameter + + + False + + + Server + + The name of the server on which the Cis REST API was opened. + + String + + String + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + SwitchParameter + + SwitchParameter + + + False + + + + + + None + + + + + + + + + + System.Object + + + + + + + + + + + + + + Example 1 + PS C:\> Disconnect-rCisServer -Server 'vcsa.domain.org' + + Closes the connection to the server vcsa.domain.org + + + + + + + + Get-rCisTag + Get + rCisTag + + Retrieves Tags from vCenter + + + + Return Tags found on the vCenter. + + + + Get-rCisTag + + Category + + The returned tags are restricted to the category with name passed on this parameter + + PSObject[] + + PSObject[] + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + Name + + Return the tag(s) with this/these name(s) + + String[] + + String[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + Get-rCisTag + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + Id + + Return the tag with the specific ID + + String[] + + String[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + + + Category + + The returned tags are restricted to the category with name passed on this parameter + + PSObject[] + + PSObject[] + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + SwitchParameter + + SwitchParameter + + + False + + + Id + + Return the tag with the specific ID + + String[] + + String[] + + + None + + + Name + + Return the tag(s) with this/these name(s) + + String[] + + String[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + SwitchParameter + + SwitchParameter + + + False + + + + + + System.Management.Automation.PSObject[] + + + + + + + + + + System.Object + + + + + + + + + + + + + + Example 1 + PS C:\> Get-rCisTag -Name MyTag + + Return the tags that are named MyTag + + + + Example 2 + PS C:\> Get-rCisTag -Name MyTag -Category MyCategory + + Return the tags that are named MyTag in the category MyCategory + + + + Example 3 + PS C:\> Get-rCisTag -Id urn:vmomi:InventoryServiceTag:385c90a7-e4ad-49af-a0a5-66fc5fedb254:GLOBAL + + Return the tag with the Id urn:vmomi:InventoryServiceTag:385c90a7-e4ad-49af-a0a5-66fc5fedb254:GLOBAL + + + + Example 4 + PS C:\> Get-rCisTagCategory -Name MyCat | Get-rCisTag + + Return all the Tags in TagCategory MyCat + + + + Example 5 + PS C:\> Get-rCisTag -Name MyTag1,MyTag2 + + Return all the Tags named MyTag1 and MyTag2 + + + + + + + + Get-rCisTagAssignment + Get + rCisTagAssignment + + Return Tag assignments + + + + Return information about all or specific Tag assignments + + + + Get-rCisTagAssignment + + Entity + + Return Tag assignments made to this entity + + PSObject[] + + PSObject[] + + + None + + + Tag + + Return Tag assignments for this Tag + + PSObject[] + + PSObject[] + + + None + + + Category + + Return only Tag assignments for Tags from this specific Category + + PSObject[] + + PSObject[] + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + + + Category + + Return only Tag assignments for Tags from this specific Category + + PSObject[] + + PSObject[] + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + SwitchParameter + + SwitchParameter + + + False + + + Entity + + Return Tag assignments made to this entity + + PSObject[] + + PSObject[] + + + None + + + Tag + + Return Tag assignments for this Tag + + PSObject[] + + PSObject[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + SwitchParameter + + SwitchParameter + + + False + + + + + + System.Management.Automation.PSObject[] + + + + + + + + + + System.Object + + + + + + + + + + + + + + Example 1 + PS C:\> Get-rCisTagAssignment + + Return all Tag assignments + + + + Example 2 + PS C:\> Get-rCisTagAssignment -Entity MyVM + + Return all Tag assignments to entity MyVM + + + + Example 3 + PS C:\> Get-rCisTagAssignment -Entity MyVM -Tag MyTag + + Return the Tag assignment to entity MyVM for a Tag with the name MyTag + + + + Example 4 + PS C:\> Get-rCisTagAssignment -Entity MyVM -Category MyCat + + Return all Tag assignments to entity MyVM with Tags from the Tag Category named MyCat + + + + Example 5 + PS C:\> Get-rCisTagAssignment -Category MyCat + + Return all Tag assignments for all Tags from the Tag Category MyCat + + + + Example 6 + PS C:\> Get-VM MyVM | Get-rCisTagAssignment + + Return all Tag assignments made to entity MyVM + + + + + + + + Get-rCisTagCategory + Get + rCisTagCategory + + Return one or more Tag Categories + + + + Return specific Tag Categories defined on the vCenter. The returned Tag Categories can be filtered by the parameters. + + + + Get-rCisTagCategory + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + Id + + The Tag Category Id + + String[] + + String[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + Get-rCisTagCategory + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + Name + + The name of the Tag Category + + String[] + + String[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + SwitchParameter + + SwitchParameter + + + False + + + Id + + The Tag Category Id + + String[] + + String[] + + + None + + + Name + + The name of the Tag Category + + String[] + + String[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + SwitchParameter + + SwitchParameter + + + False + + + + + + None + + + + + + + + + + System.Object + + + + + + + + + + + + + + Example 1 + PS C:\> Get-rCisTagCategory + + Return all Tag Categories + + + + Example 2 + PS C:\> Get-rCisTagCategory -Name Cat1,Cat2 + + Return the Tag Categories named Cat1 and Cat2 + + + + Example 3 + PS C:\> Get-rCisTagCategory -Id urn:vmomi:InventoryServiceCategory:925d8ae1-6b6e-403a-9a12-e78e14b1cdd4:GLOBAL + + Return the Tag Category with Id urn:vmomi:InventoryServiceCategory:925d8ae1-6b6e-403a-9a12-e78e14b1cdd4:GLOBAL + + + + + + + + New-rCisTag + New + rCisTag + + Create a Tag + + + + Create a Tag in one or more Categories, optionally with a Description + + + + New-rCisTag + + Name + + The Name of the new Tag + + String[] + + String[] + + + None + + + Category + + The name of the Category in which to create the Tag + + PSObject + + PSObject + + + None + + + Description + + An optional Description for the Tag + + String + + String + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + + + Category + + The name of the Category in which to create the Tag + + PSObject + + PSObject + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + SwitchParameter + + SwitchParameter + + + False + + + Description + + An optional Description for the Tag + + String + + String + + + None + + + Name + + The Name of the new Tag + + String[] + + String[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + SwitchParameter + + SwitchParameter + + + False + + + + + + System.Management.Automation.PSObject + + + + + + + + + + System.Object + + + + + + + + + + + + + + Example 1 + PS C:\> New-rCisTag -Name MyTag -Category MyCategory + + Creates a Tag named MyTag in the Category MyCategory + + + + Example 2 + PS C:\> New-rCisTag -Name MyTag + + Creates a Tag named MyTag in all Categories + + + + Example 3 + PS C:\> Get-rCisCategory -Name MyCategory | New-rCisTag -Name MyTag -Description 'Text' + + Creates a Tag named MyTag in the Category MyCategory. And add the Description 'Text' to the Tag. + + + + + + + + New-rCisTagAssignment + New + rCisTagAssignment + + Create a new Tag assignment to an Entity + + + + Create a Tag assignment to one more Entities + + + + New-rCisTagAssignment + + Tag + + The name of the Tag to assign to the entity + + String[] + + String[] + + + None + + + Entity + + The name of the Entity or the PowerCLI object for the entity + + PSObject[] + + PSObject[] + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + SwitchParameter + + SwitchParameter + + + False + + + Entity + + The name of the Entity or the PowerCLI object for the entity + + PSObject[] + + PSObject[] + + + None + + + Tag + + The name of the Tag to assign to the entity + + String[] + + String[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + SwitchParameter + + SwitchParameter + + + False + + + + + + System.Management.Automation.PSObject[] + + + + + + + + + + System.Object + + + + + + + + + + + + + + Example 1 + PS C:\> New-rCisTagAssignment -Tag MyTag -Entity MyVM + + Assign the Tag MyTag to the entity MyVM + + + + Example 2 + PS C:\> Get-VM | New-rCisTagAssignment -Tag MyTag + + Assign the Tag MyTag to all VMs + + + + + + + + New-rCisTagCategory + New + rCisTagCategory + + Create a new Tag Category + + + + Creates a new Tag Category. The user can define the Cardinality of the Tag Catgeory (default Single), add a description to the Tag Category and specify for which entity types the Tag Category can be used. + + + + New-rCisTagCategory + + Name + + The name of the new Tag Category + + String[] + + String[] + + + None + + + Cardinality + + Defines the Cardinality of the Tags in this Tag Category. Possible values are Single (default) and Multiple. + + + Single + Multiple + + String + + String + + + None + + + Description + + A description that is attached to the Tag Category + + String + + String + + + None + + + EntityType + + The type of Entity/Entities to which Tags in this Tag Category can be attached. + + String[] + + String[] + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + + + Cardinality + + Defines the Cardinality of the Tags in this Tag Category. Possible values are Single (default) and Multiple. + + String + + String + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + SwitchParameter + + SwitchParameter + + + False + + + Description + + A description that is attached to the Tag Category + + String + + String + + + None + + + EntityType + + The type of Entity/Entities to which Tags in this Tag Category can be attached. + + String[] + + String[] + + + None + + + Name + + The name of the new Tag Category + + String[] + + String[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + SwitchParameter + + SwitchParameter + + + False + + + + + + None + + + + + + + + + + System.Object + + + + + + + + + + + + + + Example 1 + PS C:\> New-rCisTagCategory -Name MyCat + + Create a new Tag Category named MyCat + + + + Example 2 + PS C:\> New-rCisTagCategory -Name MyCat -Cardinality Multiple -Description 'My Category' + + Create a new Tag Category named MyCat, with a Cardinality of Multiple and a description. + + + + + + + + Remove-rCisTag + Remove + rCisTag + + Remove a Tag + + + + Remove one or more Tags from the environment + + + + Remove-rCisTag + + Tag + + {{Fill Tag Description}} + + PSObject[] + + PSObject[] + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + Remove-rCisTag + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + Id + + {{Fill Id Description}} + + String[] + + String[] + + + None + + + + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + SwitchParameter + + SwitchParameter + + + False + + + Tag + + {{Fill Tag Description}} + + PSObject[] + + PSObject[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + SwitchParameter + + SwitchParameter + + + False + + + Id + + {{Fill Id Description}} + + String[] + + String[] + + + None + + + + + + System.Management.Automation.PSObject[] + + + + + + + + + + System.Object + + + + + + + + + + + + + + Example 1 + PS C:\> Remove-rCisTag -Name MyTag + + Remove the Tag named MyTag + + + + Example 2 + PS C:\> Remove-rCisTag -Name MyTag + + Remove the Tag named MyTag + + + + + + \ No newline at end of file diff --git a/Modules/rCisTag/rCISTag.psd1 b/Modules/rCisTag/rCISTag.psd1 new file mode 100644 index 0000000000000000000000000000000000000000..a9099d9b4397c79fbc4db9a0aa39ad2317b2deba GIT binary patch literal 5838 zcmcJTT~8ZF6o%&-ssCXmE({g8Aqf$=s1(bD1_@{cg!b0>tE>8}*kGcnf4%Md%<(Y0 z_O4@_Aj|g7&dfRQ`93rM{rkcF?Y8vUc8R-kO?T%~H*yn=`fli2?%wrWTce?75_hZF zfotgb>%xkT=4@@ljrAFdTB@}Z?Qd!IRHKReLr?ssS^20dr1ML||g1&I`7AZRV&GL^t;GN|; zPstFx64&?ozRK`Cb;qK5FRmu(M0^+{*{U5r0|J(3SZ#~!ddUxxN+&gJzUkG1o?w$W0X>_Ew2ihC;R1+?^n_ZXb zWy|H)8lp4pZwlYBxc}*;8fU22MYk{OU|r-iE)RZPYbBm}3Kyc(*Y2Q?3(**89OYsC zNWAdhuH?dl@hI~@_M-Ph_BSkLnlGYb5}(T=*P?JH4oy!Fdnay3FBt$2Av@G(mg;)@ zq+V;$y60ZUseFKFPNa=|l;^ein_rEeO@%oT8lKp3Zo8r~i$D+6ABd;rur;=I(kb}rT zmT7kslV^(R-3?{4-QSYov)3{C)OrT0H2pc4cH(=b6t}OGDU4HlVj;ES1 zw^Z-mZj5#jN39gaVtmA$O1?qk)E)X8x&of)K#nL{?hP|20bhqZud3#NLbw%!Vd=bQf`>JS9ysw%6(Ph}lBX6IVMVv)Y zj=GZR1m|OHF>1+t$UsLz*09qA89SVVn9X+$*;zVXY{wi#8B`ba^I=4~DBX{d_jc@UsWhBll zF}p8YpYM~uN}fHp9!BgrEx}kkSB|lG{qr%BxAE);{TFL<*@|+!%XU2KjjGbSSCf-R^4= zc|K1K>1v`pV4CKH5XPaidina7M|S*#%QO}x_#}Py(C|j|MYTUL~ z%UE8}NtjH7_G|ol~pHl3gF}0?h*d$OHceY3 + + Set-StrictMode -Version 2 + + # You have already run this function + if ([System.Net.ServicePointManager]::CertificatePolicy.ToString() -eq 'IgnoreCerts') { Return } + + $Domain = [AppDomain]::CurrentDomain + $DynAssembly = New-Object System.Reflection.AssemblyName('IgnoreCerts') + $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run) + $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('IgnoreCerts', $false) + $TypeBuilder = $ModuleBuilder.DefineType('IgnoreCerts', 'AutoLayout, AnsiClass, Class, Public, BeforeFieldInit', [System.Object], [System.Net.ICertificatePolicy]) + $TypeBuilder.DefineDefaultConstructor('PrivateScope, Public, HideBySig, SpecialName, RTSpecialName') | Out-Null + $MethodInfo = [System.Net.ICertificatePolicy].GetMethod('CheckValidationResult') + $MethodBuilder = $TypeBuilder.DefineMethod($MethodInfo.Name, 'PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask', $MethodInfo.CallingConvention, $MethodInfo.ReturnType, ([Type[]] ($MethodInfo.GetParameters() | % {$_.ParameterType}))) + $ILGen = $MethodBuilder.GetILGenerator() + $ILGen.Emit([Reflection.Emit.Opcodes]::Ldc_I4_1) + $ILGen.Emit([Reflection.Emit.Opcodes]::Ret) + $TypeBuilder.CreateType() | Out-Null + + # Disable SSL certificate validation + [System.Net.ServicePointManager]::CertificatePolicy = New-Object IgnoreCerts +} + +function Invoke-vCisRest{ + param ( + [String]$Method, + [String]$Request, + [PSObject]$Body + ) + + Process + { + Write-Verbose -Message "$($MyInvocation.MyCommand.Name)" + Write-Verbose -Message "`t$($PSCmdlet.ParameterSetName)" + Write-Verbose -Message "`tCalled from $($stack = Get-PSCallStack; $stack[1].Command) at $($stack[1].Location)" + + Disable-SSLValidation + + $sRest = @{ + Uri = "https:/",$Script:CisServer.Server,'rest',$Request -join '/' + Method = $Method +# Body = &{if($Body){$Body}} + Body = &{if($Body){$Body | ConvertTo-Json -Depth 32}} + ContentType = 'application/json' + Headers = &{ + if($Script:CisServer.ContainsKey('vmware-api-session-id')){ + @{ + 'vmware-api-session-id' = "$($Script:CisServer.'vmware-api-session-id')" + } + } + else{ + @{ + Authorization = "$($Script:CisServer.AuthHeader)" + } + } + } + } + Try + { +# $result = Invoke-WebRequest @sRest + $result = Invoke-RestMethod @sRest + } + Catch + { + + } + $result + } +} + +function Connect-rCisServer{ + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] + param ( + [Parameter(Mandatory, Position = 1)] + [String]$Server, + [Parameter(Mandatory = $True,ValueFromPipeline = $True, Position = 2, ParameterSetName = 'Credential')] + [System.Management.Automation.PSCredential]$Credential, + [Parameter(Mandatory = $True, Position = 2, ParameterSetName = 'PlainText')] + [String]$User, + [Parameter(Mandatory = $True, Position = 3, ParameterSetName = 'PlainText')] + [String]$Password, + [string]$Proxy, + [Parameter(DontShow)] + [switch]$Fiddler = $false + ) + + Process + { + if ($Proxy) + { + if ($PSDefaultParameterValues.ContainsKey('*:Proxy')) + { + $PSDefaultParameterValues['*:Proxy'] = $Proxy + } + else + { + $PSDefaultParameterValues.Add('*:Proxy', $Proxy) + } + if ($PSDefaultParameterValues.ContainsKey('*:ProxyUseDefaultCredentials')) + { + $PSDefaultParameterValues['*:ProxyUseDefaultCredentials'] = $True + } + else + { + $PSDefaultParameterValues.Add('*:ProxyUseDefaultCredentials', $True) + } + } + if ($PSCmdlet.ParameterSetName -eq 'PlainText') + { + $sPswd = ConvertTo-SecureString -String $Password -AsPlainText -Force + $CisCredential = New-Object System.Management.Automation.PSCredential -ArgumentList ($User, $sPswd) + } + if ($PSCmdlet.ParameterSetName -eq 'Credential') + { + $CisCredential = $Credential + } + if ($Fiddler) + { + if (Get-Process -Name fiddler -ErrorAction SilentlyContinue) + { + if ($PSDefaultParameterValues.ContainsKey('Invoke-RestMethod:Proxy')) + { + $PSDefaultParameterValues['Invoke-RestMethod:Proxy'] = 'http://127.0.0.1:8888' + } + else + { + $PSDefaultParameterValues.Add('Invoke-RestMethod:Proxy', 'http://127.0.0.1:8888') + } + } + } + $Script:CisServer = @{ + Server = $Server + AuthHeader = &{ + $User = $CisCredential.UserName + $Password = $CisCredential.GetNetworkCredential().password + + $Encoded = [System.Text.Encoding]::UTF8.GetBytes(($User, $Password -Join ':')) + $EncodedPassword = [System.Convert]::ToBase64String($Encoded) + "Basic $($EncodedPassword)" + } + } + $sRest = @{ + Method = 'Post' + Request = 'com/vmware/cis/session' + } + If($PSCmdlet.ShouldProcess("CisServer $($Server)")) + { + $result = Invoke-vCisRest @sRest + + $Script:CisServer.Add('vmware-api-session-id',$result.value) + $Script:CisServer.Remove('AuthHeader') + } + } +} + +function Disconnect-rCisServer{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High')] + param ( + [Parameter(Mandatory = $True, Position = 1)] + [String]$Server + ) + + Process + { + if($Server -ne $Script:CisServer.Server){ + Write-Warning "You are not connected to server $($Server)" + } + + $sRest = @{ + Method = 'Delete' + Request = 'com/vmware/cis/session' + } + If($PSCmdlet.ShouldProcess("CisServer $($Server)")) + { + $result = Invoke-vCisRest @sRest + $Script:CisServer.Remove('vmware-api-session-id') + } + } +} + +function Get-rCisTag{` + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low', DefaultParameterSetName='Name')] + param ( + [Parameter(Position = 1, ParameterSetName='Name')] + [String[]]$Name, + [Parameter(Position = 2, ParameterSetName='Name',ValueFromPipeline = $true)] + [PSObject[]]$Category, + [Parameter(Mandatory = $True, Position = 1, ParameterSetName='Id')] + [String[]]$Id + ) + + Process + { + if($PSCmdlet.ParameterSetName -eq 'Name'){ + if($Category){ + $tagIds = $Category | %{ + $categoryIds = &{if($_ -is [string]){ + (Get-rCisTagCategory -Name $_).Id + } + else{ + $_.Id + }} + $categoryIds | %{ + # Get all tags in categories + $sRest = @{ + Method = 'Post' + Request = "com/vmware/cis/tagging/tag/id:$([uri]::EscapeDataString($_))?~action=list-tags-for-category" + } + (Invoke-vCisRest @sRest).value + } + } + } + else{ + $sRest = @{ + Method = 'Get' + Request = 'com/vmware/cis/tagging/tag' + } + $tagIds = (Invoke-vCisRest @sRest).value + } + } + else{ + $tagIds = $Id + } + + # Get category details + $out = @() + $tagIds | where{($PSCmdlet.ParameterSetName -eq 'Id' -and $Id -contains $_) -or $PSCmdlet.ParameterSetName -eq 'Name'} | %{ + $sRest = @{ + Method = 'Get' + Request = "com/vmware/cis/tagging/tag/id:$([uri]::EscapeDataString($_))" + } + $result = Invoke-vCisRest @sRest + + if($PSCmdlet.ParameterSetName -eq 'Id' -or ($PSCmdlet.ParameterSetName -eq 'Name' -and ($Name -eq $null -or $Name -contains $result.value.name))){ + $out += New-Object PSObject -Property @{ + Description = $result.value.description + Id = $result.value.id + Name = $result.value.name + Category = (Get-rCisTagCategory -Id $result.value.category_id).Name + Uid = "$($global:defaultviserver.Id)Tag=$($result.value.id)/" + Client = $global:defaultviserver.Client + } + } + } + $out | Select-Object Category,Description,Id,Name,Uid,Client + } + +} + +function Get-rCisTagCategory{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low', DefaultParameterSetName='Name')] + param ( + [Parameter(Position = 1, ParameterSetName='Name')] + [String[]]$Name, + [Parameter(Mandatory = $True, Position = 1, ParameterSetName='Id')] + [String[]]$Id + ) + + Begin + { + $txtInfo = (Get-Culture).TextInfo + $entityTab = @{ + 'ClusterComputeResource' = 'Cluster' + 'DistributedVirtualSwitch' = 'DistributedSwitch' + 'VmwareDistributedVirtualSwitch' = 'DistributedSwitch' + 'HostSystem' = 'VMHost' + 'DistributedVirtualPortGroup' = 'DistributedPortGroup' + 'VirtualApp' = 'VApp' + 'StoragePod' = 'DatastoreCluster' + 'Network' = 'VirtualPortGroup' + } + } + + Process + { + if($PSCmdlet.ParameterSetName -eq 'Name'){ + # Get all categories + $sRest = @{ + Method = 'Get' + Request = 'com/vmware/cis/tagging/category' + } + $tagCategoryIds = (Invoke-vCisRest @sRest).value + } + else{ + $tagCategoryIds = $Id + } + + # Get category details + $out = @() + $tagCategoryids | where{($PSCmdlet.ParameterSetName -eq 'Id' -and $Id -contains $_) -or $PSCmdlet.ParameterSetName -eq 'Name'} | %{ + $sRest = @{ + Method = 'Get' + Request = "com/vmware/cis/tagging/category/id:$([uri]::EscapeDataString($_))" + } + $result = Invoke-vCisRest @sRest + if($PSCmdlet.ParameterSetName -eq 'Id' -or ($PSCmdlet.ParameterSetName -eq 'Name' -and ($Name -eq $null -or $Name -contains $result.value.name))){ + $out += New-Object PSObject -Property @{ + Description = $result.value.description + Cardinality = $txtInfo.ToTitleCase($result.value.cardinality.ToLower()) + EntityType = @(&{ + if($result.value.associable_types.Count -eq 0){'All'} + else{ + $result.value.associable_types | %{ + if($entityTab.ContainsKey($_)){ + $entityTab.Item($_) + } + else{$_} + } + }} | Sort-Object -Unique) + Id = $result.value.id + Name = $result.value.name + Uid = "$($global:defaultviserver.Id)TagCategory=$($result.value.id)/" + Client = $global:defaultviserver.Client + } + } + } + $out | Select-Object Description,Cardinality,EntityType,Id,Name,Uid,Client + } +} + +function Get-rCisTagAssignment{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')] + param ( + [parameter(Position = 1, ValueFromPipeline = $true)] + [PSObject[]]$Entity, + [parameter(Position = 2)] + [PSObject[]]$Tag, + [parameter(Position = 3)] + [PSObject[]]$Category + ) + + Begin + { + if($Category.Count -ne 0 -or $Tag.Count -ne 0){ + $tagIds = @((Get-rCisTag -Name $Tag -Category $Category).Id) + } + else{ + $tagIds = @((Get-rCisTag).Id) + } + $out = @() + } + + Process + { + foreach($ent in $Entity){ + if($ent -is [string]){ + $ent = Get-Inventory -Name $ent -ErrorAction SilentlyContinue + } + + $entMoRef = New-Object PSObject -Property @{ + type = $ent.ExtensionData.MoRef.Type + id = $ent.ExtensionData.MoRef.Value + } + $sRest = @{ + Method = 'Post' + Request = 'com/vmware/cis/tagging/tag-association?~action=list-attached-tags-on-objects' + Body = @{ + object_ids = @($entMoRef) + } + } + $tagObj = (Invoke-vCisRest @sRest).value + foreach($obj in @($tagObj)){ + foreach($tag in ($obj.tag_ids | where{$tagIds -contains $_})){ + $sMoRef = "$($obj.object_id.type)-$($obj.object_id.id)" + $out += New-Object PSObject -Property @{ + Entity = (Get-View -id $sMoRef -Property Name).Name + Tag = (Get-rCisTag -Id $tag).Name + Id = 'com.vmware.cis.tagging.TagAssociationModel' + Name = 'com.vmware.cis.tagging.TagAssociationModel' + Uid = "$($global:defaultviserver.Id)VirtualMachine=$($sMoRef)/TagAssignment=/Tag=$($tag.tag_id)/" + Client = $global:defaultviserver.Client + } + } + } + } + } + + End + { + if($out.Count -eq 0) + { + $sRest = @{ + Method = 'Post' + Request = 'com/vmware/cis/tagging/tag-association?~action=list-attached-objects-on-tags' + Body = @{ + tag_ids = $tagIds + } + } + $tagObj = (Invoke-vCisRest @sRest).value + $out = foreach($tag in @(($tagObj | where{$tagIds -contains $_.tag_id}))){ + foreach($obj in $tag.object_ids){ + $sMoRef = "$($obj.type)-$($obj.id)" + New-Object PSObject -Property @{ + Entity = (Get-View -id $sMoRef -Property Name).Name + Tag = (Get-rCisTag -Id $tag.tag_id).Name + Id = 'com.vmware.cis.tagging.TagAssociationModel' + Name = 'com.vmware.cis.tagging.TagAssociationModel' + Uid = "$($global:defaultviserver.Id)VirtualMachine=$($sMoRef)/TagAssignment=/Tag=$($tag.tag_id)/" + Client = $global:defaultviserver.Client + } + } + } + } + + $out | Select-Object Uid,Tag,Entity,Id,Name,Client + } +} + +function New-rCisTag{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High')] + param ( + [Parameter(Mandatory=$true, Position = 1)] + [String[]]$Name, + [Parameter(Mandatory=$true, Position = 2,ValueFromPipeline = $true)] + [PSObject]$Category, + [Parameter(Position = 3)] + [string]$Description + ) + + Process + { + $out = @() + if($Category -is [String]){ + $Category = Get-rCisTagCategory -Name $Category + } + $Name | %{ + $sRest = @{ + Method = 'Post' + Request = 'com/vmware/cis/tagging/tag' + Body = @{ + create_spec = @{ + category_id = $Category.Id + name = $_ + description = $Description + } + } + } + $tagId = (Invoke-vCisRest @sRest).value + $out += New-Object PSObject -Property @{ + Category = $Category.Name + Description = $Description + Id = $tagId + Name = $_ + Uid = "$($global:defaultviserver.Id)Tag=$($tagId)/" + Client = $global:defaultviserver.Client + } + } + $out | Select-Object Category,Description,Id,Name,Uid,Client + } +} + +function New-rCisTagCategory{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High')] + param ( + [Parameter(Mandatory=$true, Position = 1)] + [String[]]$Name, + [Parameter(Position = 2)] + [ValidateSet('Single','Multiple')] + [string]$Cardinality = 'Single', + [Parameter(Position = 3)] + [string]$Description, + [Parameter(Position = 4)] + [string[]]$EntityType + ) + + Process + { + $out = @() + $Name | %{ + $sRest = @{ + Method = 'Post' + Request = 'com/vmware/cis/tagging/category' + Body = @{ + create_spec = @{ + cardinality = $Cardinality.ToUpper() + associable_types = @($EntityType) + name = $_ + description = $Description + } + } + } + $categoryId = (Invoke-vCisRest @sRest).value + $out += New-Object PSObject -Property @{ + Description = $Description + Cardinality = $Cardinality + EntityType = @($EntityType) + Id = $categoryId + Name = $_ + Uid = "$($global:defaultviserver.Id)TagCategory=$($categoryId)/" + Client = $global:defaultviserver.Client + } + } + $out | Select-Object Description,Cardinality,EntityType,Id,Name,Uid,Client + } +} + +function New-rCisTagAssignment{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High')] + param ( + [Parameter(Mandatory=$true, Position = 1)] + [String[]]$Tag, + [Parameter(Mandatory=$true,ValueFromPipeline = $true, Position = 2)] + [PSObject[]]$Entity + ) + + Process + { + $tagIds = @((Get-rCisTag -Name $Tag).Id) + $Entity = foreach($ent in $Entity){ + if($ent -is [string]){ + $ent = Get-Inventory -Name $ent -ErrorAction SilentlyContinue + } + $entMoRef = New-Object PSObject -Property @{ + type = $ent.ExtensionData.MoRef.Type + id = $ent.ExtensionData.MoRef.Value + } + foreach($tagId in $tagIds){ + $sRest = @{ + Method = 'Post' + Request = "com/vmware/cis/tagging/tag-association/id:$($tagId)?~action=attach" + Body = @{ + object_id = $entMoRef + } + } + Invoke-vCisRest @sRest + } + } + } + +# foreach($ent in +# if($Tag.Count -eq 1) +# { +# $tagId = (Get-rCisTag -Name $Tag).Id +# } +# elseif($Tag.Count -gt 1) +# { +# $tagIds = (Get-rCisTag -Name $Tag).Id +# } +# $Entity = foreach($ent in $Entity){ +# if($ent -is [string]){ +# Get-Inventory -Name $ent -ErrorAction SilentlyContinue +# } +# else{$ent} +# } +# +# if($Entity.Count -eq 1) +# { +# $entMoRef = New-Object PSObject -Property @{ +# type = $Entity[0].ExtensionData.MoRef.Type +# id = $Entity[0].ExtensionData.MoRef.Value +# } +# if($tag.Count -eq 1){ +# $sRest = @{ +# Method = 'Post' +# Request = "com/vmware/cis/tagging/tag-association/id:$($tagId)?~action=attach" +# Body = @{ +# object_id = $entMoRef +# } +# } +# Invoke-vCisRest @sRest +# } +# elseif($Tag.Count -gt 1){ +# $sRest = @{ +# Method = 'Post' +# Request = 'com/vmware/cis/tagging/tagassociation?~action=attach-multiple-tags-to-object' +# Body = @{ +# object_id = $entMoRef +# tag_ids = @($tagIds) +# } +# } +# Invoke-vCisRest @sRest +# } +# } +# elseif($Entity.Count -gt 1) +# { +# $entMorefs = $Entity | %{ +# New-Object PSObject -Property @{ +# type = $_.ExtensionData.MoRef.Type +# id = $_.ExtensionData.MoRef.Value +# } +# } +# if($tag.Count -eq 1){ +# $sRest = @{ +# Method = 'Post' +# Request = 'com/vmware/cis/tagging/tagassociation/id:$($tagId)?~action=attach-tag-to-multiple-objects' +# Body = @{ +# objects_ids = @($entMoRefs) +# tag_id = $tagId +# } +# } +# Invoke-vCisRest @sRest +# } +# elseif($Tag.Count -gt 1){ +# $tagIds | %{ +# $sRest = @{ +# Method = 'Post' +# Request = 'com/vmware/cis/tagging/tagassociation/id:$($tagId)?~action=attach-tag-to-multiple-objects' +# Body = @{ +# objects_ids = @($entMoRefs) +# tag_id = $_ +# } +# } +# Invoke-vCisRest @sRest +# } +# } +# } +# } +} + +function Remove-rCisTag{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High', DefaultParameterSetName='Name')] + param ( + [Parameter(Mandatory=$true, Position = 1, ValueFromPipeline = $true,ParameterSetName='Name')] + [PSObject[]]$Tag, + [Parameter(Mandatory=$true, Position = 1, ValueFromPipelineByPropertyName = $true,ParameterSetName='Id')] + [String[]]$Id + ) + + Process + { + if($PSCmdlet.ParameterSetName -eq 'Name'){ + foreach($tagObj in $Tag){ + if($tagObj -is [string]){ + $tagObj = Get-rCisTag -Name $tagObj + } + $sRest = @{ + Method = 'Delete' + Request = "com/vmware/cis/tagging/tag/id:$($tagObj.Id)" + } + Invoke-vCisRest @sRest + } + } + else{ + foreach($tagId in $Id){ + $sRest = @{ + Method = 'Delete' + Request = "com/vmware/cis/tagging/tag/id:$($tagId)" + } + Invoke-vCisRest @sRest + } + } + } +} + +function Remove-rCisTagCategory{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High', DefaultParameterSetName='Name')] + param ( + [Parameter(Mandatory=$true,Position = 1, ValueFromPipeline = $true,ParameterSetName='Name')] + [PSObject[]]$Category, + [Parameter(Mandatory=$true,Position = 1, ValueFromPipelineByPropertyName = $true,ParameterSetName='Id')] + [String[]]$Id + ) + + Process + { + if($PSCmdlet.ParameterSetName -eq 'Name'){ + foreach($catObj in $Category){ + if($catObj -is [string]){ + $catObj = Get-rCisTagCategory -Name $catObj + } + $sRest = @{ + Method = 'Delete' + Request = "com/vmware/cis/tagging/category/id:$($catObj.Id)" + } + Invoke-vCisRest @sRest + } + } + else{ + foreach($catId in $Id){ + $sRest = @{ + Method = 'Delete' + Request = "com/vmware/cis/tagging/category/id:$($catId)" + } + Invoke-vCisRest @sRest + } + } + } +} + +function Remove-rCisTagAssignment{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High',DefaultParameterSetName='Assignment')] + param ( + [Parameter(Mandatory=$true, Position = 1, ValueFromPipeline = $true,ParameterSetName='Assignment')] + [PSObject[]]$TagAssignment, + [Parameter(Mandatory=$true,Position = 1, ValueFromPipeline = $true,ParameterSetName='Name')] + [string[]]$Tag, + [Parameter(Position = 2, ParameterSetName='Name')] + [string[]]$Category, + [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName = $true,ParameterSetName='Id')] + [string[]]$TagId, + [Parameter(ParameterSetName='Name')] + [Parameter(ParameterSetName='Id')] + [PSObject[]]$Entity + ) + + Process + { + + switch ($PSCmdlet.ParameterSetName){ + 'Name' { + $TagAssignment = Get-rCisTagAssignment -Entity $Entity -Tag $Tag -Category $Category + } + 'Id' { + $tags = Get-rCisTag -Id $TagId + $TagAssignment = Get-rCisTagAssignment -Tag $tags.Name -Entity $Entity + } + } + if($TagAssignment){ + $entMoRefs = @(Get-Inventory -Name $TagAssignment.Entity -ErrorAction SilentlyContinue | %{ + New-Object PSObject -Property @{ + type = $_.ExtensionData.MoRef.Type + id = $_.ExtensionData.MoRef.Value + } + }) + $tagIds = @((Get-rCisTag -Name $TagAssignment.Tag).Id) + } + + foreach($entMoRef in $entMoRefs){ + foreach($tId in $tagIds){ + $sRest = @{ + Method = 'Post' + Request = "com/vmware/cis/tagging/tag-association/id:$($tId)?~action=detach" + Body = @{ + object_id = $entMoRef + } + } + Invoke-vCisRest @sRest + } + } + } +} + +function Set-rCisTag{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High')] + param ( + [Parameter(Mandatory=$true, Position = 1, ValueFromPipeline = $true)] + [PSObject[]]$Tag, + [Parameter(Position = 2)] + [string]$Name, + [Parameter(Position = 3)] + [string]$Description + ) + + Process + { + foreach($tagObj in $Tag){ + if($tagObj -is [string]){ + $tagObj = Get-rCisTag -Name $tagObj + } + $sRest = @{ + Method = 'Patch' + Request = "com/vmware/cis/tagging/tag/id:$($tagObj.Id)" + Body = @{ + update_spec = @{ + name = $Name + description = $Description + } + } + } + Invoke-vCisRest @sRest + } + } +} + +function Set-rCisTagCategory{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High')] + param ( + [Parameter(Mandatory=$true, Position = 1, ValueFromPipeline = $true)] + [PSObject[]]$Category, + [Parameter(Position = 2)] + [string]$Name, + [Parameter(Position = 3)] + [ValidateSet('Single','Multiple')] + [string]$Cardinality, # Only SINGLE to MULTIPLE +# [string[]]$AddEntityType, # Does not work + [string]$Description + ) + + Process + { + foreach($catObj in $Category){ + if($catObj -is [string]){ + $catObj = Get-rCisTagCategory -Name $catObj + } + $sRest = @{ + Method = 'Patch' + Request = "com/vmware/cis/tagging/category/id:$($catObj.Id)" + Body = @{ + update_spec = @{ + } + } + } + if($Name){ + $sRest.Body.update_spec.Add('name',$Name) + } + if($Description){ + $sRest.Body.update_spec.Add('description',$Description) + } + if($Cardinality -and $catObj.Cardinality -eq 'SINGLE'){ + $sRest.Body.update_spec.Add('cardinality',$Cardinality.ToUpper()) + } + if($Name -or $Description -or $Cardinality){ + Invoke-vCisRest @sRest + } + } + } +} From 6c50bef798a2e3a23c6f3af75ddd1e637f19db7d Mon Sep 17 00:00:00 2001 From: LucD Date: Sat, 2 Dec 2017 23:25:35 +0100 Subject: [PATCH 24/28] rCisTag-Examples Add examples to rCisTag module --- Modules/rCisTag/Examples/01-Get.ps1 | 17 ++++++++++++++++ Modules/rCisTag/Examples/02-New.ps1 | 14 +++++++++++++ Modules/rCisTag/Examples/03-Set.ps1 | 11 ++++++++++ Modules/rCisTag/Examples/04-Remove.ps1 | 13 ++++++++++++ Modules/rCisTag/Examples/05-Tag-Datastore.ps1 | 20 +++++++++++++++++++ Modules/rCisTag/Examples/CisConfig.ps1 | 3 +++ 6 files changed, 78 insertions(+) create mode 100644 Modules/rCisTag/Examples/01-Get.ps1 create mode 100644 Modules/rCisTag/Examples/02-New.ps1 create mode 100644 Modules/rCisTag/Examples/03-Set.ps1 create mode 100644 Modules/rCisTag/Examples/04-Remove.ps1 create mode 100644 Modules/rCisTag/Examples/05-Tag-Datastore.ps1 create mode 100644 Modules/rCisTag/Examples/CisConfig.ps1 diff --git a/Modules/rCisTag/Examples/01-Get.ps1 b/Modules/rCisTag/Examples/01-Get.ps1 new file mode 100644 index 0000000..52cf4de --- /dev/null +++ b/Modules/rCisTag/Examples/01-Get.ps1 @@ -0,0 +1,17 @@ +# Fetch Cis Server hostname and credentials +.\CisConfig.ps1 + + +Connect-rCisServer -Server $cisServer -User $cisUser -Password $cisPswd + +# Get Tag information +Get-rCisTag + +# Get Tag Category information +Get-rCisTagCategory + +# Get Tag Assignment information +Get-rCisTagAssignment + +Disconnect-rCisServer -Server $cisServer -Confirm:$false + \ No newline at end of file diff --git a/Modules/rCisTag/Examples/02-New.ps1 b/Modules/rCisTag/Examples/02-New.ps1 new file mode 100644 index 0000000..7fe9af2 --- /dev/null +++ b/Modules/rCisTag/Examples/02-New.ps1 @@ -0,0 +1,14 @@ +# Fetch Cis Server hostname and credentials +.\CisConfig.ps1 + +Connect-rCisServer -Server $cisServer -User $cisUser -Password $cisPswd + +New-rCisTagCategory -Name MyCat1 -Cardinality Single -Description 'Test Tag Category' -EntityType 'VirtualMachine' +New-rCisTag -Name MyTag1 -Category MyCat1 -Description 'Test Tag' +$vm = Get-VM | Get-Random +New-rCisTagAssignment -Entity $vm -Tag MyTag1 + +Get-rCisTagAssignment -Tag MyTag1 + +Disconnect-rCisServer -Server $cisServer -Confirm:$false + \ No newline at end of file diff --git a/Modules/rCisTag/Examples/03-Set.ps1 b/Modules/rCisTag/Examples/03-Set.ps1 new file mode 100644 index 0000000..35d26b0 --- /dev/null +++ b/Modules/rCisTag/Examples/03-Set.ps1 @@ -0,0 +1,11 @@ +# Fetch Cis Server hostname and credentials +.\CisConfig.ps1 + +Connect-rCisServer -Server $cisServer -User $cisUser -Password $cisPswd + +Get-rCisTag -Name MyTag1 | Set-rCisTag -Name MyNewTag1 -Description 'Name changed' + +Get-rCisTagCategory -Name MyCat1 | Set-rCisTagCategory -Cardinality Multiple -Name MyNewCat1 -Description 'Name changed' + +Disconnect-rCisServer -Server $cisServer -Confirm:$false + \ No newline at end of file diff --git a/Modules/rCisTag/Examples/04-Remove.ps1 b/Modules/rCisTag/Examples/04-Remove.ps1 new file mode 100644 index 0000000..2f684f9 --- /dev/null +++ b/Modules/rCisTag/Examples/04-Remove.ps1 @@ -0,0 +1,13 @@ +# Fetch Cis Server hostname and credentials +.\CisConfig.ps1 + +Connect-rCisServer -Server $cisServer -User $cisUser -Password $cisPswd + +Get-rCisTagAssignment -Tag MyNewTag1 | Remove-rCisTagAssignment -Confirm:$false + +Get-rCisTag -Name MyNewTag1 | Remove-rCisTag -Confirm:$false + +Get-rCisTagCategory -Name MyNewCat1 | Remove-rCisTagCategory -Confirm:$false + +Disconnect-rCisServer -Server $cisServer -Confirm:$false + \ No newline at end of file diff --git a/Modules/rCisTag/Examples/05-Tag-Datastore.ps1 b/Modules/rCisTag/Examples/05-Tag-Datastore.ps1 new file mode 100644 index 0000000..f0ad343 --- /dev/null +++ b/Modules/rCisTag/Examples/05-Tag-Datastore.ps1 @@ -0,0 +1,20 @@ +# Fetch Cis Server hostname and credentials +.\CisConfig.ps1 + +Connect-rCisServer -Server $cisServer -User $cisUser -Password $cisPswd + +$catName = 'Homelab' + +# Clean up +Get-rCisTagCategory -Name $catName | Remove-rCisTagCategory -Confirm:$false + +# Tag all datastores with their type +New-rCisTagCategory -Name HomeLab -Description 'Homelab datastores' -Cardinality Single -EntityType 'Datastore' | +New-rCisTag -Name 'VMFS','NFS' -Description 'Datastore type' + +Get-Cluster -Name Cluster1 | Get-Datastore | %{ + New-rCisTagAssignment -Entity $_ -Tag "$($_.Type)" +} + +Disconnect-rCisServer -Server $cisServer -Confirm:$false + \ No newline at end of file diff --git a/Modules/rCisTag/Examples/CisConfig.ps1 b/Modules/rCisTag/Examples/CisConfig.ps1 new file mode 100644 index 0000000..de72021 --- /dev/null +++ b/Modules/rCisTag/Examples/CisConfig.ps1 @@ -0,0 +1,3 @@ +$cisServer = 'vcsa.my.domain' +$cisUser = 'administrator@vsphere.local' +$cisPswd = 'VMware1!' From b5800f0eff9eb4e16a1fe93b8ea1827d709f072f Mon Sep 17 00:00:00 2001 From: William Lam Date: Wed, 20 Dec 2017 08:37:38 -0800 Subject: [PATCH 25/28] PowerCLI Module using Cross vCenter Migration Utility Fling API --- Modules/CrossvCentervmotion/XVM.psm1 | 290 +++++++++++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 Modules/CrossvCentervmotion/XVM.psm1 diff --git a/Modules/CrossvCentervmotion/XVM.psm1 b/Modules/CrossvCentervmotion/XVM.psm1 new file mode 100644 index 0000000..aef65c8 --- /dev/null +++ b/Modules/CrossvCentervmotion/XVM.psm1 @@ -0,0 +1,290 @@ +Function Get-XVCMStatus { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function returns whether Cross vCenter Workload Migration Utility is running or not + .EXAMPLE + Get-XVCMStatus +#> + $Uri = "http://localhost:8080/api/ping" + + $results = Invoke-WebRequest -Uri $Uri -Method GET -TimeoutSec 5 + + if($results.StatusCode -eq 200) { + Write-Host -ForegroundColor Green $results.Content + } else { Write-Host -ForegroundColor Red "Cross vCenter Workload Migration Utility is probably not running" } +} + +Function Get-XVCMSite { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function returns all registered vCenter Servers + .EXAMPLE + Get-XVCMSite +#> + $Uri = "http://localhost:8080/api/sites" + + $results = Invoke-WebRequest -Uri $Uri -Method GET + + if($results.StatusCode -eq 200) { + ($results.Content | ConvertFrom-Json)|select sitename,hostname,username + } else { Write-Host -ForegroundColor Red "Failed to retrieve VC Site Registration details" } +} + +Function New-XVCMSite { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function registers a new vCenter Server endpoint + .PARAMETER SiteName + The display name for the particular vCenter Server to be registered + .PARAMETER VCHostname + The Hostname/IP Address of vCenter Server + .PARAMETER VCUsername + The VC Username of vCenter Server + .PARAMETER VCPassword + The VC Password of vCenter Server + .PARAMETER Insecure + Flag to disable SSL Verification checking, useful for lab environments + .EXAMPLE + New-XVCMSite -SiteName "SiteA" -VCHostname "vcenter65-1.primp-industries.com" -VCUsername "administrator@vsphere.local" -VCPassword "VMware1!" -Insecure +#> + param( + [Parameter(Mandatory=$true)][String]$SiteName, + [Parameter(Mandatory=$true)][String]$VCHostname, + [Parameter(Mandatory=$true)][String]$VCUsername, + [Parameter(Mandatory=$true)][String]$VCPassword, + [Parameter(Mandatory=$false)][Switch]$Insecure + ) + + $Uri = "http://localhost:8080/api/sites" + + $insecureFlag = $false + if($Insecure) { + $insecureFlag = $true + } + + $body = @{ + "sitename"=$SiteName; + "hostname"=$VCHostname; + "username"=$VCUsername; + "password"=$VCPassword; + "insecure"=$insecureFlag; + } + + $body = $body | ConvertTo-Json + + Write-Host -ForegroundColor Cyan "Registering vCenter Server $VCHostname as $SiteName ..." + $results = Invoke-WebRequest -Uri $Uri -Method POST -Body $body -ContentType "application/json" + + if($results.StatusCode -eq 200) { + Write-Host -ForegroundColor Green "Successfully registered $SiteName" + } else { Write-Host -ForegroundColor Red "Failed to register $SiteName" } +} + +Function Remove-XVCMSite { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function removes vCenter Server endpoint + .PARAMETER SiteName + The name of the registered vCenter Server to remove + .EXAMPLE + Remove-XVCMSite -SiteName "SiteA" +#> + param( + [Parameter(Mandatory=$true)][String]$SiteName + ) + + $Uri = "http://localhost:8080/api/sites/$SiteName" + + Write-Host -ForegroundColor Cyan "Deleting vCenter Server Site Registerion $SiteName ..." + $results = Invoke-WebRequest -Uri $Uri -Method DELETE + + if($results.StatusCode -eq 200) { + Write-Host -ForegroundColor Green "Successfully deleted $SiteName" + } else { Write-Host -ForegroundColor Red "Failed to deleted $SiteName" } +} + +Function New-XVCMRequest { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function initiates a migration request + .PARAMETER SrcSite + The name of the source vCenter Server + .PARAMETER DstSite + The name of the destination vCenter Server + .PARAMETER SrcDatacenter + The name of the source vSphere Datacenter + .PARAMETER DstDatacenter + The name of the destination vSphere Datacenter + .PARAMETER SrcCluster + The name of the source vSphere Cluster + .PARAMETER DstCluster + The name of the destination vSphere Cluster + .PARAMETER DstDatastore + The name of the destination Datastore + .PARAMETER srcVMs + List of VMs to migrate + .PARAMETER NetworkMapping + Hash table of the VM network mappings between your source and destination vCenter Server + .EXAMPLE + New-XVCMRequest -SrcSite SiteA -DstSite SiteB ` + -SrcDatacenter Datacenter-SiteA -DstDatacenter Datacenter-SiteB ` + -SrcCluster Palo-Alto -DstCluster Santa-Barbara ` + -DstDatastore vsanDatastore ` + -srcVMs @("PhotonOS-01","PhotonOS-02","PhotonOS-03","PhotonOS-04") ` + -NetworkMapping @{"DVPG-VM Network 1"="DVPG-Internal Network";"DVPG-VM Network 2"="DVPG-External Network"} +#> + param( + [Parameter(Mandatory=$true)][String]$SrcSite, + [Parameter(Mandatory=$true)][String]$DstSite, + [Parameter(Mandatory=$true)][String]$SrcDatacenter, + [Parameter(Mandatory=$true)][String]$DstDatacenter, + [Parameter(Mandatory=$true)][String]$SrcCluster, + [Parameter(Mandatory=$true)][String]$DstCluster, + [Parameter(Mandatory=$true)][String]$DstDatastore, + [Parameter(Mandatory=$true)][String[]]$srcVMs, + [Parameter(Mandatory=$true)][Hashtable]$NetworkMapping + ) + + $Uri = "http://localhost:8080/api/tasks" + + $body = @{ + "sourceSite"=$SrcSite; + "targetSite"=$DstSite; + "sourceDatacenter"=$SrcDatacenter; + "targetDatacenter"=$dstDatacenter; + "sourceCluster"=$SrcCluster; + "targetCluster"=$DstCluster; + "targetDatastore"=$DstDatastore; + "networkMap"=$NetworkMapping; + "vmList"=$srcVMs; + } + + $body = $body | ConvertTo-Json + + Write-Host -ForegroundColor Cyan "Initiating migration request ..." + $results = Invoke-WebRequest -Uri $Uri -Method POST -Body $body -ContentType "application/json" + + if($results.StatusCode -eq 200) { + $taskId = ($results.Content | ConvertFrom-Json).requestId + Write-Host -ForegroundColor Green "Successfully issued migration with TaskID: $taskId" + } else { Write-Host -ForegroundColor Red "Failed to initiate migration request" } +} + +Function Get-XVCMTask { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function retrieves either all migration tasks and/or a specific migration task + .PARAMETER Id + The task ID returned from initiating a migration + .EXAMPLE + Get-XVCMTask -Id +#> + param( + [Parameter(Mandatory=$false)][String]$Id + ) + + $Uri = "http://localhost:8080/api/tasks" + + if($Id) { + $body = @{"requestId"=$Id} + + $results = Invoke-WebRequest -Uri $Uri -Method GET -Body $body -ContentType "application/json" + } else { + $results = Invoke-WebRequest -Uri $Uri -Method GET + } + + if($results.StatusCode -eq 200) { + $results.Content | ConvertFrom-Json + } else { Write-Host -ForegroundColor Red "Failed to retrieve tasks" } +} + +Function Get-VMNetwork { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function returns the list of all VM Networks attached to + given VMs to help with initiating migration + .PARAMETER srcVMs + List of VMs to query their current VM Networks + .EXAMPLE + Get-VMNetwork -srcVMs @("PhotonOS-01","PhotonOS-02","PhotonOS-03","PhotonOS-04") +#> + param( + [Parameter(Mandatory=$false)][String[]]$srcVMs + ) + + if (-not $global:DefaultVIServers) { Write-Host -ForegroundColor red "No vCenter Server Connection found, please connect to your source vCenter Server using Connect-VIServer"; break } + + $results = @() + if($srcVMs) { + foreach ($srcVM in $srcVMs) { + $vm = Get-VM -Name $srcVM + $networkDetails = $vm | Get-NetworkAdapter + $tmp = [pscustomobject] @{ + Name = $srcVM; + Adapter = $networkDetails.name; + Network = $networkDetails.NetworkName; + } + $results+=$tmp + } + } else { + foreach ($vm in Get-VM) { + $networkDetails = $vm | Get-NetworkAdapter + $tmp = [pscustomobject] @{ + Name = $vm.Name; + Adapter = $networkDetails.name; + Network = $networkDetails.NetworkName; + } + $results+=$tmp + } + } + $results +} \ No newline at end of file From 23f215be3596fbc3b89e25a963ddef69cbd0a7d7 Mon Sep 17 00:00:00 2001 From: Kyle Ruddy Date: Fri, 5 Jan 2018 16:13:39 -0500 Subject: [PATCH 26/28] Update VMToolsManagement.psm1 Added advanced function: Get-VMToolsUpgradePolicy Updated the following advanced functions to add functionatlity: - Set-VMToolsUpgradePolicy - Supports UpgradeAtPowerCycle and Manual - Update-VMToolsConfInVM - Supports all log levels now Misc other minor updates: - cmdlets changed to 'advanced function' - 'vcetner' changed to 'vcenter' --- .../VMToolsManagement/VMToolsManagement.psm1 | 257 ++++++++++++------ 1 file changed, 173 insertions(+), 84 deletions(-) diff --git a/Modules/VMToolsManagement/VMToolsManagement.psm1 b/Modules/VMToolsManagement/VMToolsManagement.psm1 index bbfdf5e..335476d 100644 --- a/Modules/VMToolsManagement/VMToolsManagement.psm1 +++ b/Modules/VMToolsManagement/VMToolsManagement.psm1 @@ -1,4 +1,4 @@ -# Script Module : VMToolsManagement +# Script Module : VMToolsManagement # Version : 1.0 # Copyright © 2017 VMware, Inc. All Rights Reserved. @@ -37,10 +37,10 @@ New-VIProperty -Name ToolsBuildNumber -Object VirtualMachine -Value { Function Get-VMToolsInfo { <# .SYNOPSIS - This cmdlet retrieves the VMTools info of specified virtual machines. + This advanced function retrieves the VMTools info of specified virtual machines. .DESCRIPTION - This cmdlet retrieves the VMTools version and build number info of specified virtual machines. + This advanced function retrieves the VMTools version and build number info of specified virtual machines. .PARAMETER VM Specifies the virtual machines which you want to get the VMTools info of. @@ -50,7 +50,7 @@ Function Get-VMToolsInfo { C:\PS> $VCServer = Connect-VIServer -Server -User -Password C:\PS> Get-VM -Server $VCServer | Get-VMToolsInfo - Retrieves VMTools info of all virtual machines which run in the $VCServer vCetner Server. + Retrieves VMTools info of all virtual machines which run in the $VCServer vCenter Server. .EXAMPLE C:\PS> Get-VM "*rhel*" | Get-VMToolsInfo @@ -74,7 +74,7 @@ Function Get-VMToolsInfo { Retrieves VMTools info of virtual machines which run on the "MyESXiHostName" ESXi host. .NOTES - This cmdlet assumes that you are connected to at least one vCenter Server system. + This advanced function assumes that you are connected to at least one vCenter Server system. The tools build number is not supported in VMTools before 10.2.0 .NOTES @@ -100,17 +100,17 @@ Function Get-VMToolsInfo { ) Process { - Get-VM $VM | Select Name, @{Name="ToolsVersion"; Expression={$_.Guest.ToolsVersion}}, ToolsBuildNumber + Get-VM $VM | Select-Object Name, @{Name="ToolsVersion"; Expression={$_.Guest.ToolsVersion}}, ToolsBuildNumber } } Function Get-VMToolsInstallLastError { <# .SYNOPSIS - This cmdlet retrieves the error code of last VMTools installation. + This advanced function retrieves the error code of last VMTools installation. .DESCRIPTION - This cmdlet retrieves the error code of last VMTools installation on specified virtual machines. + This advanced function retrieves the error code of last VMTools installation on specified virtual machines. .PARAMETER VM Specifies the virtual machines which you want to get the error code of. @@ -120,7 +120,7 @@ Function Get-VMToolsInstallLastError { C:\PS> $VCServer = Connect-VIServer -Server -User -Password C:\PS> Get-VM -Server $VCServer | Get-VMToolsInstallLastError - Retrieves the last VMTools installation error code of all virtual machines which run in the $VCServer vCetner Server. + Retrieves the last VMTools installation error code of all virtual machines which run in the $VCServer vCenter Server. .EXAMPLE C:\PS> Get-VM "*win*" | Get-VMToolsInstallLastError @@ -144,7 +144,7 @@ Function Get-VMToolsInstallLastError { Retrieves the last VMTools installation error code of virtual machines which run on the "MyESXiHostName" ESXi host. .NOTES - This cmdlet assumes that you are connected to at least one vCenter Server system. + This advanced function assumes that you are connected to at least one vCenter Server system. .NOTES Author : Daoyuan Wang @@ -171,7 +171,7 @@ Function Get-VMToolsInstallLastError { Process { $result = @() foreach ($_ in $VM) { - $errorCodeInfo = $_.ExtensionData.Config.ExtraConfig.GetEnumerator() | where {$_.Key -eq "guestinfo.toolsInstallErrCode"} + $errorCodeInfo = $_.ExtensionData.Config.ExtraConfig.GetEnumerator() | Where-Object {$_.Key -eq "guestinfo.toolsInstallErrCode"} $info = New-Object PSObject $info | Add-Member -type NoteProperty -name VmName -value $_.Name @@ -186,10 +186,10 @@ Function Get-VMToolsInstallLastError { Function Get-VMToolsGuestInfo { <# .SYNOPSIS - This cmdlet retrieves the guest info of specified virtual machines. + This advanced function retrieves the guest info of specified virtual machines. .DESCRIPTION - This cmdlet retrieves the guest info such as HostName, IP, ToolsStatus, ToolsVersion, + This advanced function retrieves the guest info such as HostName, IP, ToolsStatus, ToolsVersion, ToolsInstallType and GuestFamily of specified virtual machines. .PARAMETER VM @@ -200,7 +200,7 @@ Function Get-VMToolsGuestInfo { C:\PS> $VCServer = Connect-VIServer -Server -User -Password C:\PS> Get-VM -Server $VCServer | Get-VMToolsGuestInfo - Retrieves guest info of all virtual machines which run in the $VCServer vCetner Server. + Retrieves guest info of all virtual machines which run in the $VCServer vCenter Server. .EXAMPLE C:\PS> Get-VM "*win*" | Get-VMToolsGuestInfo @@ -236,7 +236,7 @@ Function Get-VMToolsGuestInfo { Retrieves guest info of virtual machines which run on the "MyESXiHostName" ESXi host. .NOTES - This cmdlet assumes that you are connected to at least one vCenter Server system. + This advanced function assumes that you are connected to at least one vCenter Server system. .NOTES Author : Daoyuan Wang @@ -261,7 +261,7 @@ Function Get-VMToolsGuestInfo { ) Process { - Get-VM $VM | Select Name, @{Name="HostName"; Expression={$_.Guest.HostName}}, + Get-VM $VM | Select-Object Name, @{Name="HostName"; Expression={$_.Guest.HostName}}, @{Name="IP"; Expression={$_.Guest.ExtensionData.IpAddress}}, @{Name="ToolsStatus"; Expression={$_.Guest.ExtensionData.ToolsStatus}}, @{Name="ToolsVersion"; Expression={$_.Guest.ToolsVersion}}, @@ -274,10 +274,10 @@ Function Get-VMToolsGuestInfo { Function Get-VMByToolsInfo { <# .SYNOPSIS - This cmdlet retrieves the virtual machines with specified VMTools info. + This advanced function retrieves the virtual machines with specified VMTools info. .DESCRIPTION - This cmdlet retrieves the virtual machines with specified VMTools version, + This advanced function retrieves the virtual machines with specified VMTools version, running status or version status. .PARAMETER VM @@ -297,7 +297,7 @@ Function Get-VMByToolsInfo { C:\PS> $VCServer = Connect-VIServer -Server -User -Password C:\PS> Get-VM -Server $VCServer | Get-VMByToolsInfo - Retrieves the virtual machines with VMTools not running in vCetner Server $VCServer. + Retrieves the virtual machines with VMTools not running in vCenter Server $VCServer. .EXAMPLE C:\PS> Get-VM | Get-VMByToolsInfo -ToolsRunningStatus guestToolsNotRunning @@ -328,7 +328,7 @@ Function Get-VMByToolsInfo { Retrieves the virtual machines with VMTools that need to upgrade on the "MyESXiHostName" ESXi host. .NOTES - This cmdlet assumes that you are connected to at least one vCenter Server system. + This advanced function assumes that you are connected to at least one vCenter Server system. .NOTES Author : Daoyuan Wang @@ -361,9 +361,9 @@ Function Get-VMByToolsInfo { [String] $ToolsRunningStatus, [Parameter(Mandatory=$false)] - [ValidateSet("guestToolsNotInstalled", - "guestToolsNeedUpgrade", - "guestToolsCurrent", + [ValidateSet("guestToolsNotInstalled", + "guestToolsNeedUpgrade", + "guestToolsCurrent", "guestToolsUnmanaged")] [String] $ToolsVersionStatus ) @@ -376,65 +376,60 @@ Function Get-VMByToolsInfo { } if ($ToolsVersion) { - $vmList = $vmList | Where {$_.Guest.ToolsVersion -like $ToolsVersion} + $vmList = $vmList | Where-Object {$_.Guest.ToolsVersion -like $ToolsVersion} } if ($ToolsRunningStatus) { - $vmList = $vmList | Where {$_.Guest.ExtensionData.ToolsRunningStatus -eq $ToolsRunningStatus} + $vmList = $vmList | Where-Object {$_.Guest.ExtensionData.ToolsRunningStatus -eq $ToolsRunningStatus} } if ($ToolsVersionStatus) { - $vmList = $vmList | Where {$_.Guest.ExtensionData.ToolsVersionStatus -eq $ToolsVersionStatus} + $vmList = $vmList | Where-Object {$_.Guest.ExtensionData.ToolsVersionStatus -eq $ToolsVersionStatus} } $vmList } } -Function Set-VMToolsUpgradePolicy { +Function Get-VMToolsUpgradePolicy { <# .SYNOPSIS - This cmdlet sets the VMTool's upgrade policy to "upgradeAtPowerCycle". + This advanced function retrieves the VMTools upgrade policy info of specified virtual machines. .DESCRIPTION - This cmdlet sets the VMTool's upgrade policy to "upgradeAtPowerCycle" of specified virtual machines. + This advanced function retrieves the VMTools upgrade policy info of specified virtual machines. .PARAMETER VM - Specifies the virtual machines which you want to set the VMTool's upgrade policy of. + Specifies the virtual machines which you want to query VMTools status of. .EXAMPLE - C:\PS> Import-Module .\VMToolsManagement.psm1 - C:\PS> $VCServer = Connect-VIServer -Server -User -Password - C:\PS> Get-VM -Server $VCServer | Set-VMToolsUpgradePolicy - - Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of all virtual machines in the $VCServer vCetner Server. + C:\PS> Get-VM "*rhel*" | Get-VMToolsUpgradePolicy + Name VMToolsUpgradePolicy + ------ ---------------------- + 111394-RHEL-6.8-0 manual + 111394-RHEL-6.8-1 manual + 111393-RHEL-Server-7.2 upgradeAtPowerCycle + Retrieves VMTools upgrade policy info of virtual machines with name containing "rhel". .EXAMPLE - C:\PS> Get-VM "*win*" | Set-VMToolsUpgradePolicy - - Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of virtual machines with name containing "win". + C:\PS> Get-VM -Location "MyClusterName" | Get-VMToolsUpgradePolicy + Retrieves VMTools upgrade policy info from virtual machines which run in the "MyClusterName" cluster. .EXAMPLE - C:\PS> Get-VM -Location "MyClusterName" | Set-VMToolsUpgradePolicy - - Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of virtual machines in the "MyClusterName" cluster. - -.EXAMPLE - C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Set-VMToolsUpgradePolicy - - Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of virtual machines on the "MyESXiHostName" ESXi host. + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Get-VMToolsUpgradePolicy + Retrieves VMTools upgrade policyinfo of virtual machines which run on the "MyESXiHostName" ESXi host. .NOTES - This cmdlet assumes that you are connected to at least one vCenter Server system. + This advanced function assumes that you are connected to at least one vCenter Server system. .NOTES - Author : Daoyuan Wang - Author email : daoyuanw@vmware.com + Author : Kyle Ruddy + Author email : kmruddy@gmail.com Version : 1.0 ==========Tested Against Environment========== - VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) - VMware vCenter Server Version : 6.5 (build 4602587) - PowerCLI Version : PowerCLI 6.5 (build 4624819) + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 7388607) + VMware vCenter Server Version : 6.5 (build 7312210) + PowerCLI Version : PowerCLI 6.5 (build 7155375) PowerShell Version : 5.1 #> @@ -448,8 +443,81 @@ Function Set-VMToolsUpgradePolicy { [ValidateNotNullOrEmpty()] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM ) + + Process { + + Get-VM $VM | Select-Object Name, @{Name="VMToolsUpgradePolicy"; Expression={$_.ExtensionData.Config.Tools.ToolsUpgradePolicy}} + + } + +} + +Function Set-VMToolsUpgradePolicy { +<# +.SYNOPSIS + This advanced function sets the VMTool's upgrade policy to either "manual" or "upgradeAtPowerCycle". + +.DESCRIPTION + This advanced function sets the VMTool's upgrade policy to either "manual" or "upgradeAtPowerCycle" of specified virtual machines. + +.PARAMETER VM + Specifies the virtual machines which you want to set the VMTool's upgrade policy of. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password + C:\PS> Get-VM -Server $VCServer | Set-VMToolsUpgradePolicy -UpgradePolicy manual + + Sets VMTool's upgrade policy to "manual" of all virtual machines in the $VCServer vCenter Server. + +.EXAMPLE + C:\PS> Get-VM "*win*" | Set-VMToolsUpgradePolicy -UpgradePolicy upgradeAtPowerCycle + + Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of virtual machines with name containing "win". + +.EXAMPLE + C:\PS> Get-VM -Location "MyClusterName" | Set-VMToolsUpgradePolicy -UpgradePolicy upgradeAtPowerCycle + + Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of virtual machines in the "MyClusterName" cluster. + +.EXAMPLE + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Set-VMToolsUpgradePolicy -UpgradePolicy manual + + Sets VMTool's upgrade policy to "manual" of virtual machines on the "MyESXiHostName" ESXi host. + +.NOTES + This advanced function assumes that you are connected to at least one vCenter Server system. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.1 + Update Author : Kyle Ruddy + Update email : kmruddy@gmail.com + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106)(build 7388607) + VMware vCenter Server Version : 6.5 (build 4602587)(build 7312210) + PowerCLI Version : PowerCLI 6.5 (build 4624819)(build 7155375) + PowerShell Version : 5.1 +#> + + [CmdletBinding(SupportsShouldProcess)] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM, + + [Parameter(Mandatory=$false, + Position = 1)] + [ValidateSet("upgradeAtPowerCycle", + "manual")] + [String] $UpgradePolicy + ) Begin { - $UpgradePolicy = "upgradeAtPowerCycle" $vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec $vmConfigSpec.Tools = New-Object VMware.Vim.ToolsConfigInfo $vmConfigSpec.Tools.ToolsUpgradePolicy = $UpgradePolicy @@ -463,6 +531,7 @@ Function Set-VMToolsUpgradePolicy { if ($vmView.Config.Tools.ToolsUpgradePolicy -ne $UpgradePolicy) { Write-Verbose "Applying 'upgradeAtPowerCycle' setting to $($_.Name)..." $vmView.ReconfigVM($vmConfigSpec) + Get-VMToolsUpgradePolicy -VM $_ } } } @@ -471,10 +540,10 @@ Function Set-VMToolsUpgradePolicy { Function Invoke-VMToolsListProcessInVM { <# .Synopsis - This cmdlet lists the processes in the virtual machine. + This advanced function lists the processes in the virtual machine. .Description - This cmdlet lists the running processes in the virtual machine. + This advanced function lists the running processes in the virtual machine. .PARAMETER VM Specifies the virtual machine which you want to list the processes of. @@ -503,7 +572,7 @@ Function Invoke-VMToolsListProcessInVM { List the processes in the "MyVMName" VM. .NOTES - This cmdlet lists processes in the guest OS of virtual machine. + This advanced function lists processes in the guest OS of virtual machine. A VMTools should already be running in the guest OS. .NOTES @@ -559,10 +628,10 @@ Function Invoke-VMToolsListProcessInVM { Function Update-VMToolsImageLocation { <# .Synopsis - This cmdlet updates the link /productLocker in ESXi host. + This advanced function updates the link /productLocker in ESXi host. .Description - This cmdlet updates the link /productLocker in ESXi host directly to avoid host reboot. + This advanced function updates the link /productLocker in ESXi host directly to avoid host reboot. .Parameter VMHost Specifies the ESXi host on which you want to update the /productLocker link. @@ -574,7 +643,7 @@ Function Update-VMToolsImageLocation { Specifies the password you want to use for authenticating with the ESXi host. .Parameter ImageLocation - Specifies the new image location where you want /producterLocker to link. + Specifies the new image location Where-Object you want /producterLocker to link. .Example C:\PS> Import-Module .\VMToolsManagement.psm1 @@ -586,9 +655,9 @@ Function Update-VMToolsImageLocation { Update the link /producterLocker on $SampleHost to point to '/locker/packages/6.5.0/'. .NOTES - This cmdlet connects to ESXi host to execute shell command directly. + This advanced function connects to ESXi host to execute shell command directly. Make sure the SSH service on ESXi host is enabled, and a SSH library(Posh-SSH or SSH-Sessions etc.) - for powershell is already installed on client where you call This cmdlet. + for powershell is already installed on client Where-Object you call this advanced function. You can instal Posh-SSH by executing: iex (New-Object Net.WebClient).DownloadString("https://gist.github.com/darkoperator/6152630/raw/c67de4f7cd780ba367cccbc2593f38d18ce6df89/instposhsshdev") For SSH-Sessions installation and usage, please refer to @@ -628,7 +697,7 @@ Function Update-VMToolsImageLocation { Process { if (-not (Get-Command New-SSHSession)) { - Throw "This cmdlet depends on SSH library. Please ensure a SSH library is already installed!" + Throw "This advanced function depends on SSH library. Please ensure a SSH library is already installed!" } $password = new-object System.Security.SecureString @@ -656,18 +725,21 @@ Function Update-VMToolsImageLocation { } } -Function Update-VMToolsConfInVM { +Function Set-VMToolsConfInVM { <# .Synopsis - This cmdlet updates the tools.conf content in guest OS. + This advanced function sets the tools.conf content in guest OS. .Description - This cmdlet copies the tools.conf in gueset OS of virtual machine to localhost, - then updates it locally by setting "vmtoolsd.level = info" and copies it back to the guest OS. + This advanced function copies the tools.conf in gueset OS of virtual machine to localhost, + then sets it locally by setting "vmtoolsd.level" to a valid level and copies it back to the guest OS. .PARAMETER VM Specifies the virtual machine to update. +.PARAMETER LogLevel + Specifies the desired log level to log. + .Parameter GuestUser Specifies the user name you want to use for authenticating with the guest OS. @@ -684,16 +756,18 @@ Function Update-VMToolsConfInVM { Updates the tools.conf in $SampleVM, changes the vmtoolsd log level to info ("vmtoolsd.level = info") for example. .NOTES - This cmdlet updates the tools.conf in guest OS. A VMTools should already be running in the guest OS. + This advanced function updates the tools.conf in guest OS. A VMTools should already be running in the guest OS. .NOTES Author : Daoyuan Wang Author email : daoyuanw@vmware.com - Version : 1.0 + Version : 1.1 + Update Author : Kyle Ruddy + Update email : kmruddy@gmail.com ==========Tested Against Environment========== - VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) - VMware vCenter Server Version : 6.5 (build 4602587) - PowerCLI Version : PowerCLI 6.5 (build 4624819) + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106)(build 7388607) + VMware vCenter Server Version : 6.5 (build 4602587)(build 7312210) + PowerCLI Version : PowerCLI 6.5 (build 4624819)(build 7155375) PowerShell Version : 5.1 #> @@ -707,6 +781,17 @@ Function Update-VMToolsConfInVM { [ValidateNotNullOrEmpty()] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM, + [Parameter(Mandatory=$true, + Position = 1)] + [ValidateSet("none", + "critical", + "error", + "warning", + "message", + "info", + "debug")] + [String] $LogLevel, + [Parameter(Mandatory=$true)] [String] $GuestUser, @@ -756,7 +841,7 @@ Function Update-VMToolsConfInVM { # Updates tools.conf by setting vmtoolsd.level = info, just for example. ############################################################################# $confContent = Get-Content $localToolsConfFile - $updatedContent = "vmtoolsd.level = info" + $updatedContent = "vmtoolsd.level = $LogLevel" Write-Verbose "Editing tools.conf (set 'vmtoolsd.level = info' for example)..." if ($confContent -match "vmtoolsd\.level") { @@ -775,19 +860,23 @@ Function Update-VMToolsConfInVM { -GuestUser $GuestUser -GuestPassword $GuestPassword -Force -ErrorAction:Stop } catch { Write-Error "Failed to update tools.conf of $VM" + Write-Verbose "Removing the local tools configuration file" + Remove-Item $localToolsConfFile return } Write-Host "The tools.conf updated in $VM successfully." -ForegroundColor Green + Write-Verbose "Removing the local tools configuration file" + Remove-Item $localToolsConfFile } } Function Invoke-VMToolsVIBInstall { <# .SYNOPSIS - This cmdlet installs VMTool VIB in ESXi hosts. + This advanced function installs VMTool VIB in ESXi hosts. .DESCRIPTION - This cmdlet installs VMTool VIB in specified ESXi hosts. + This advanced function installs VMTool VIB in specified ESXi hosts. .PARAMETER VMHost Specifies the ESXi hosts which you want to install VMTool VIB in. @@ -816,7 +905,7 @@ Function Invoke-VMToolsVIBInstall { Installs VMTool VIB in ESXi host of the "MyClusterName" cluster. .NOTES - This cmdlet assumes that you are connected to at least one vCenter Server system. + This advanced function assumes that you are connected to at least one vCenter Server system. .NOTES Author : Daoyuan Wang @@ -846,7 +935,7 @@ Function Invoke-VMToolsVIBInstall { foreach ($_ in $VMHost) { $esxcli = Get-EsxCLI -VMHost $_ -V2 - $result = $esxcli.software.vib.list.Invoke() | where {$_.name -match 'tools'} + $result = $esxcli.software.vib.list.Invoke() | Where-Object {$_.name -match 'tools'} Write-Verbose "Existing tools VIB on $_ before installing: $($result.Name)_$($result.Version)" # Install VIBs @@ -861,7 +950,7 @@ Function Invoke-VMToolsVIBInstall { Write-Error "Failed to install VMTools VIB package!" } else { Write-Verbose $result.Message - $result = $esxcli.software.vib.list.Invoke() | where {$_.name -match 'tools'} + $result = $esxcli.software.vib.list.Invoke() | Where-Object {$_.name -match 'tools'} Write-Verbose "Tools VIB on $_ after installing: $($result.Name)_$($result.Version)" Write-Host "VMTools VIB package installed on $_ successfully." -ForegroundColor Green } @@ -872,10 +961,10 @@ Function Invoke-VMToolsVIBInstall { Function Invoke-VMToolsUpgradeInVMs { <# .SYNOPSIS - This cmdlet upgrades VMTools to the version bundled by ESXi host. + This advanced function upgrades VMTools to the version bundled by ESXi host. .DESCRIPTION - This cmdlet upgrades VMTools of specified virtual machines to the version + This advanced function upgrades VMTools of specified virtual machines to the version bundled by ESXi host. You can also specify the number of virtual machines to upgrade in parallel. @@ -896,7 +985,7 @@ Function Invoke-VMToolsUpgradeInVMs { C:\PS> $VCServer = Connect-VIServer -Server -User -Password C:\PS> Get-VM -Server $VCServer | Invoke-VMToolsUpgradeInVMs -MaxParallelUpgrades 5 - Upgrades VMTools of all virtual machines in the $VCServer vCetner Server, 5 at a time in parallel. + Upgrades VMTools of all virtual machines in the $VCServer vCenter Server, 5 at a time in parallel. .EXAMPLE C:\PS> Get-VM | Invoke-VMToolsUpgradeInVMs -GuestOSType windows -MaxParallelUpgrades 1 | ft -Autosize @@ -929,7 +1018,7 @@ Function Invoke-VMToolsUpgradeInVMs { Upgrades VMTools of virtual machines on the "MyESXiHostName" ESXi host, 5 at a time. .NOTES - This cmdlet assumes an old VMTools is already running in the virtual machine. + This advanced function assumes an old VMTools is already running in the virtual machine. .NOTES Author : Daoyuan Wang @@ -1026,7 +1115,7 @@ Function Invoke-VMToolsUpgradeInVMs { # Load PowerCLI module and connect to VCServer, as child thread environment is independent with parent if(-not $global:DefaultVIServer) { $moduleName = "vmware.vimautomation.core" - if(-not (Get-Module | Where {$_.name -eq $moduleName})) { + if(-not (Get-Module | Where-Object {$_.name -eq $moduleName})) { try { Import-Module $moduleName -ErrorAction SilentlyContinue | Out-Null } @@ -1130,7 +1219,7 @@ Function Invoke-VMToolsUpgradeInVMs { End { #Verify all threads completed - while (($jobs | Where {$_.Handle.iscompleted -ne ‘Completed’}).Count -gt 0) { + while (($jobs | Where-Object {$_.Handle.iscompleted -ne ‘Completed’}).Count -gt 0) { Start-Sleep -Seconds 5 } @@ -1146,4 +1235,4 @@ Function Invoke-VMToolsUpgradeInVMs { } } -Export-ModuleMember *-* \ No newline at end of file +Export-ModuleMember *-* From 02286dbe53f7196003c4ab0ad71c3cf139dd204c Mon Sep 17 00:00:00 2001 From: Kyle Ruddy Date: Tue, 9 Jan 2018 14:55:28 -0500 Subject: [PATCH 27/28] Update VMToolsManagement.psm1 Update the quotes on line 1222 so that the module import no longer errors out. --- Modules/VMToolsManagement/VMToolsManagement.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/VMToolsManagement/VMToolsManagement.psm1 b/Modules/VMToolsManagement/VMToolsManagement.psm1 index 335476d..df6e2e8 100644 --- a/Modules/VMToolsManagement/VMToolsManagement.psm1 +++ b/Modules/VMToolsManagement/VMToolsManagement.psm1 @@ -1219,7 +1219,7 @@ Function Invoke-VMToolsUpgradeInVMs { End { #Verify all threads completed - while (($jobs | Where-Object {$_.Handle.iscompleted -ne ‘Completed’}).Count -gt 0) { + while (($jobs | Where-Object {$_.Handle.iscompleted -ne "Completed"}).Count -gt 0) { Start-Sleep -Seconds 5 } From 5bee9abf629f2e16eda72dda891fa8b2eac14f88 Mon Sep 17 00:00:00 2001 From: cloudcowboyco Date: Thu, 11 Jan 2018 15:57:17 -0500 Subject: [PATCH 28/28] Fixing spelling errors and grammar issues --- README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 7d2825c..86afe3e 100644 --- a/README.md +++ b/README.md @@ -59,15 +59,15 @@ The repository has been provided to allow the community to share resources that 1. Browse to the appropriate section (example: Scripts) 2. Select the “Create new file” button 3. On the new page, enter a file name, enter the resource’s information -4. Within the “Commit new file” area, enter the title and description, then select “Create a new branch for this commit…” and enter a sensical branch name +4. Within the “Commit new file” area, enter the title and description, then select “Create a new branch for this commit…” and enter a sensible branch name 5. Click “Propose new file” 6. On the “Open a pull request” page, click “Create pull request” #### GitHub - Upload files Option 1. Browse to the appropriate section (example: Modules) 2. Select the “Upload files” button -3. On the new page, drag or choose the files to add -4. Within the “Commit changes” area, enter the title and description, then select “Create a new branch for this commit…” and enter a sensical branch name +3. On the new page, drag or choose the files to add +4. Within the “Commit changes” area, enter the title and description, then select “Create a new branch for this commit…” and enter a sensible branch name 5. Click “Propose new file” 6. On the “Open a pull request” page, click “Create pull request” @@ -88,7 +88,7 @@ The following information must be included with each submitted scripting resourc #### Note Placement Examples: Script: Top few lines Module: Module manifest - + #### Required Script Note Example: `<#` `Script name: script_name.ps1` @@ -126,7 +126,7 @@ The following information should be included when possible. Inclusion of informa This section describes guidelines put in place to maintain a standard of quality while also promoting broader contribution. ### General Best Practices ### Resource Naming -* Give the resource a name that is indicitive of the actions and/or results of its running +* Give the resource a name that is indicative of the actions and/or results of its running ### Fault Handling * Read and apply the following basic fault handling where applicable: Microsoft’s Hey, Scripting Guy! Blog: https://blogs.technet.microsoft.com/heyscriptingguy/2014/07/09/handling-errors-the-powershell-way/ @@ -138,7 +138,7 @@ This section describes guidelines put in place to maintain a standard of quality * Avoid changing any global variables ### Help Information -* All resources should have inline documentation. +* All resources should have inline documentation. ### Scripts * The script should be easy to read and understand @@ -149,27 +149,27 @@ This section describes guidelines put in place to maintain a standard of quality * Use only standard verbs ### Security -* Usage of PowerShell’s strict mode is preferred, but not required. +* Usage of PowerShell’s strict mode is preferred, but not required. * Remove any information related to one’s own environment (examples: Passwords, DNS/IP Addresses, custom user credentials, etc) ## Resource Maintenance ### Maintenance Ownership -Ownership of any and all submitted resources are maintained by the submitter. This ownership also includes maintenance of any and all submitted resources. +Ownership of any and all submitted resources are maintained by the submitter. This ownership also includes maintenance of any and all submitted resources. ### Filing Issues -Any bugs or other issues should be filed within GitHub by way of the repository’s Issue Tracker. -### Resolving Issues -Any community member can resolve issues within the repository, however only the owner or a board member can approve the update. Once approved, assuming the resolution involves a pull request, only a board member will be able to merge and close the request. +Any bugs or other issues should be filed within GitHub by way of the repository’s Issue Tracker. +### Resolving Issues +Any community member can resolve issues within the repository, however only the owner or a board member can approve the update. Once approved, assuming the resolution involves a pull request, only a board member will be able to merge and close the request. ## Additional Resources ### Discussions Join in on the discussion within the VMware Code Slack team's PowerCLI channel: ### VMware Sample Exchange -It is highly recommened to add any and all submitted resources to the VMware Sample Exchange: - +It is highly recommended to add any and all submitted resources to the VMware Sample Exchange: + Sample Exchange can be allowed to access your GitHub resources, by way of a linking process, where they can be indexed and searched by the community. There are VMware social media accounts which will advertise resources posted to the site and there's no additional accounts needed, as the VMware Sample Exchange uses MyVMware credentials. ## VMWARE TECHNOLOGY PREVIEW LICENSE AGREEMENT -The VMware Technnology Preview License Agreement: +The VMware Technology Preview License Agreement: # Repository Administrator Resources ## Table of Contents @@ -180,7 +180,7 @@ The VMware Technnology Preview License Agreement: