I have exported into CSV file the VMs and the Folder Paths in format:
Name Path
Not having much luck importing these to move the VMs to the folder structure (which is already in place). Can anyone give me some suggestions of Code to try? Thanks.
After some further analysis, the following script worked.
<#
.SYNOPSIS Retrieve folders by giving a path
.DESCRIPTION The function will retrieve a folder by it's path.
The path can contain any type of leave (folder or datacenter).
.NOTES
Author: Luc Dekens .PARAMETER Path The path to the folder. This is a required parameter.
.PARAMETER
Path The path to the folder. This is a required parameter.
.PARAMETER
Separator The character that is used to separate the leaves in the path. The default is '/'
.EXAMPLE
PS> Get-FolderByPath -Path "Folder1/Datacenter/Folder2"
.EXAMPLE
PS> Get-FolderByPath -Path "Folder1>Folder2" -Separator '>'
#>
param(
[CmdletBinding()]
[parameter(Mandatory = $true)]
[System.String[]]${Path},
[char]${Separator} = '/'
)
process {
if ((Get-PowerCLIConfiguration).DefaultVIServerMode -eq "Multiple") {
$vcs = $global:defaultVIServers
}
else {
$vcs = $global:defaultVIServers[0]
}
foreach ($vc in $vcs) {
$si = Get-View ServiceInstance -Server $vc
$rootName = (Get-View -Id $si.Content.RootFolder -Property Name).Name
foreach ($strPath in $Path) {
$root = Get-Folder -Name $rootName -Server $vc -ErrorAction SilentlyContinue
$strPath.Split($Separator) | ForEach-Object {
$root = Get-Inventory -Name $_ -Location $root -Server $vc -ErrorAction SilentlyContinue
if ((Get-Inventory -Location $root -NoRecursion | Select-Object -ExpandProperty Name) -contains "vm") {
$root = Get-Inventory -Name "vm" -Location $root -Server $vc -NoRecursion
}
}
$root | Where-Object { $_ -is [VMware.VimAutomation.ViCore.Impl.V1.Inventory.FolderImpl] } | ForEach-Object {
Get-Folder -Name $_.Name -Location $root.Parent -NoRecursion -Server $vc
}
}
}
}
}
Import-Module -Name VMware.PowerCLI
If ($globale:DefaultVIServers) {
Disconnect-VIServer -Server $global:DefaultVIServers -Force -ErrorAction SilentlyContinue
}
$destVI = Read-Host "Please enter name or IP address of the vCenter"
$creds = Get-Credential -Message 'Enter credentials for $destVI'
$datacenter = Read-Host 'Please enter name of the Datacenter'
Connect-VIServer -server $destVI -Credential $creds
# move the vm's to correct location
Import-Csv "c:\csv-files\04-$($datacenter)-vms-with-FolderPath.csv" |
ForEach-Object -Process {
$pathStr = $_.FolderPath.Replace("\$($_.VMName)",'').TrimStart('\')
$folder = Get-FolderByPath -Path $pathStr -Separator '\'
$vm = Get-VM -Name $_.VMName
Move-VM -VM $vm -Destination $vm.VMHost -InventoryLocation $folder -Confirm:$false
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
It would help if you tell us in which format that folder path is in the CSV file.
And perhaps share the code you are using and which errors you are getting.
You might want to have a look at my Folder By Path post.
Once you have the Folder object, a simple Move-VM with the InventoryLocation parameter should do the trick.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
I will check out your page. I am very new to this!!
The CSV:
TestVM \DC\TestFolder\SubTestFolder\
VM name is 1st colum and path is second column.
Code:
Get-Module -Name VMware* -ListAvailable | Import-Module
If ($globale:DefaultVIServers) {
Disconnect-VIServer -Server $global:DefaultVIServers -Force
}
$destVI = Read-Host "Please enter name or IP address of the destination Server"
$datacenter = Read-Host "DataCenter naam in VC"
$creds = get-credential
connect-viserver -server $destVI -Credential $creds
# move the vm's to correct location
$VMfolder = @()
$VMfolder = import-csv "c:\csv-files\04-$($
foreach($guest in $VMfolder){
$key = @()
$key = Split-Path $guest.Path | split-path -leaf
if ($key -eq $datacenter) {
Write-Host "Root folder $guest.path"
##
Move-VM (Get-VM $guest.Name) -Destination "vm"
}
else
{
Move-VM (Get-VM $guest.Name) -Destination (Get-folder $key)
}
}
Disconnect-VIServer "*" -Confirm:$False
ERROR:
WARNING: Specifying Folder in the Destination parameter is deprecated and the parameter will stop accepting Folder
objects at a future release. Please use the InventoryLocation parameter instead.
Move-VM : 2/16/2020 12:35:58 AM Move-VM Server task failed: The request refers to an unexpected or unknown type.
At C:\temp\CheapDisasterRecovery\
+ Move-VM (Get-VM $guest.Name) -Destination (Get-folder $key)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Move-VM], VimException
+ FullyQualifiedErrorId : Security_Impl_
You could try something like this
<#
.SYNOPSIS Retrieve folders by giving a path
.DESCRIPTION The function will retrieve a folder by it's path.
The path can contain any type of leave (folder or datacenter).
.NOTES
Author: Luc Dekens .PARAMETER Path The path to the folder. This is a required parameter.
.PARAMETER
Path The path to the folder. This is a required parameter.
.PARAMETER
Separator The character that is used to separate the leaves in the path. The default is '/'
.EXAMPLE
PS> Get-FolderByPath -Path "Folder1/Datacenter/Folder2"
.EXAMPLE
PS> Get-FolderByPath -Path "Folder1>Folder2" -Separator '>'
#>
param(
[CmdletBinding()]
[parameter(Mandatory = $true)]
[System.String[]]${Path},
[char]${Separator} = '/'
)
process {
if ((Get-PowerCLIConfiguration).DefaultVIServerMode -eq "Multiple") {
$vcs = $global:defaultVIServers
}
else {
$vcs = $global:defaultVIServers[0]
}
foreach ($vc in $vcs) {
$si = Get-View ServiceInstance -Server $vc
$rootName = (Get-View -Id $si.Content.RootFolder -Property Name).Name
foreach ($strPath in $Path) {
$root = Get-Folder -Name $rootName -Server $vc -ErrorAction SilentlyContinue
$strPath.Split($Separator) | ForEach-Object {
$root = Get-Inventory -Name $_ -Location $root -Server $vc -ErrorAction SilentlyContinue
if ((Get-Inventory -Location $root -NoRecursion | Select-Object -ExpandProperty Name) -contains "vm") {
$root = Get-Inventory -Name "vm" -Location $root -Server $vc -NoRecursion
}
}
$root | Where-Object { $_ -is [VMware.VimAutomation.ViCore.Impl.V1.Inventory.FolderImpl] } | ForEach-Object {
Get-Folder -Name $_.Name -Location $root.Parent -NoRecursion -Server $vc
}
}
}
}
}
Import-Module -Name VMware*
If ($globale:DefaultVIServers) {
Disconnect-VIServer -Server $global:DefaultVIServers -Force -ErrorAction SilentlyContinue
}
$destVI = Read-Host "Please enter name or IP address of the vCenter"
$creds = Get-Credential -Message 'Enter credentials for $destVI'
$datacenter = Read-Host 'Please enter name of the Datacenter'
Connect-VIServer -server $destVI -Credential $creds
# move the vm's to correct location
Import-Csv "c:\csv-files\04-$($datacenter)-vms-with-FolderPath.csv" |
ForEach-Object -Process {
Move-VM -VM $_.Name -InventoryLocation (Get-FolderByPath -Path ($_.Path.TrimStart('\')))
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
What do you mean?
The above script just moves VMs to the folder indicated in the CSV (and so did your original script).
Is this a new requirement?
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Errors when I run this. First error is when I first run the script before I enter in VC info:
Import-Module : The specified module 'VMware*' was not loaded because no valid module file was found in any module
directory.
At C:\temp\move_folders_vms.ps1:50 char:1
+ Import-Module -Name VMware*
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (VMware*:String) [Import-Module], FileNotFoundException
+ FullyQualifiedErrorId : Modules_ModuleNotFound,Microsoft.PowerShell.Commands.ImportModuleCommand
Errors after I enter in VC info:
Move-VM : 2/16/2020 10:02:54 AM Move-VM Value cannot be found for the mandatory parameter VM
At C:\temp\move_folders_vms.ps1:66 char:5
+ Move-VM -VM $_.Name -InventoryLocation (Get-FolderByPath -Path ($ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Move-VM], VimException
+ FullyQualifiedErrorId : Core_BaseCmdlet_UnknownError,VMware.VimAutomation.ViCore.Cmdlets.Commands.MoveVM
Ok, let's check what is installed.
Run the following
If that doesn't return anything, then run
And to check what PowerShell version you are using, check what the following returns
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
No the location of the VMs shouldn't be an issue.
But the loading of the PowerCLI modules seems to be one.
Try this on its own
Check if the modules are actually loaded with
If they are not loaded, check what is in
$env:PSModulePath
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
PS C:\temp> Import-Module -Name VMware *
Import-Module : A positional parameter cannot be found that accepts argument '*'.
At line:1 char:1
+ Import-Module -Name VMware *
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Import-Module], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.ImportModuleCommand
PS C:\temp> Get-Module -Name VMware *
Get-Module : A positional parameter cannot be found that accepts argument '*'.
At line:1 char:1
+ Get-Module -Name VMware *
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-Module], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.GetModuleCommand
PS C:\temp> $env:PSModulePath
D:\Users\scoraccie\Documents\WindowsPowerShell\Modules;C:\Program Files\WindowsPowerShell\Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules
There is no blank between VMware and *
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
PS C:\temp> Import-Module -Name VMware*
Import-Module : The specified module 'VMware*' was not loaded because no valid module file was found in any module
directory.
At line:1 char:1
+ Import-Module -Name VMware*
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (VMware*:String) [Import-Module], FileNotFoundException
+ FullyQualifiedErrorId : Modules_ModuleNotFound,Microsoft.PowerShell.Commands.ImportModuleCommand
PS C:\temp> Get-Module -Name VMware*
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 6.7.0.1... VMware.DeployAutomation {Add-DeployRule, Add-ProxyServer, Add-ScriptBundle, Copy-D...
Script 6.7.0.1... VMware.ImageBuilder {Add-EsxSoftwareDepot, Add-EsxSoftwarePackage, Compare-Esx...
Manifest 11.5.0.... VMware.PowerCLI
Script 6.7.0.1... VMware.Vim
Script 11.5.0.... VMware.VimAutomation.Cis.Core {Connect-CisServer, Disconnect-CisServer, Get-CisService}
Script 11.0.0.... VMware.VimAutomation.Cloud {Add-CIDatastore, Connect-CIServer, Disconnect-CIServer, G...
Script 11.5.0.... VMware.VimAutomation.Common {Get-Task, Stop-Task, Wait-Task}
Script 11.5.0.... VMware.VimAutomation.Core {Add-PassthroughDevice, Add-VirtualSwitchPhysicalNetworkAd...
Script 11.5.0.... VMware.VimAutomation.Hcx {Connect-HCXServer, Disconnect-HCXServer, Get-HCXAppliance...
Script 7.10.0.... VMware.VimAutomation.HorizonView {Connect-HVServer, Disconnect-HVServer}
Script 11.3.0.... VMware.VimAutomation.License Get-LicenseDataManager
Script 11.5.0.... VMware.VimAutomation.Nsxt {Connect-NsxtServer, Disconnect-NsxtServer, Get-NsxtPolicy...
Script 11.5.0.... VMware.VimAutomation.Sdk {Get-ErrorReport, Get-InstallPath, Get-PSVersion}
Script 11.0.0.... VMware.VimAutomation.Security {Get-SecurityInfo, Get-VTpm, Get-VTpmCertificate, Get-VTpm...
Script 11.5.0.... VMware.VimAutomation.Srm {Connect-SrmServer, Disconnect-SrmServer}
Script 11.5.0.... VMware.VimAutomation.Storage {Add-KeyManagementServer, Add-VsanObjectToRepairQueue, Cop...
Script 1.3.0.0 VMware.VimAutomation.StorageUtility Update-VmfsDatastore
Script 11.2.0.... VMware.VimAutomation.Vds {Add-VDSwitchPhysicalNetworkAdapter, Add-VDSwitchVMHost, E...
Script 11.5.0.... VMware.VimAutomation.Vmc {Add-VmcSddcHost, Connect-Vmc, Disconnect-Vmc, Get-AwsAcco...
Script 10.0.0.... VMware.VimAutomation.vROps {Connect-OMServer, Disconnect-OMServer, Get-OMAlert, Get-O...
Script 6.5.1.7... VMware.VumAutomation {Add-EntityBaseline, Copy-Patch, Get-Baseline, Get-Complia...
Ok, in the script I provided earlier, replace the line
with
and try the script again.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Getting different error now:
You cannot call a method on a null-valued expression.
At C:\temp\move_folders_vms.ps1:
+ Move-VM -VM $_.Name -InventoryLocation (Get-FolderByPath -Path ($ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
It looks like the CSV file might have a problem.
What does the following return?
Import-Csv "c:\csv-files\04-$($datacenter)-vms-with-FolderPath.csv"
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference