In the beginning there was Get-VM
No, actually not, in the beginning there is get-help, try to memorize that, GET HELP. Easy no ? Get dash help, after that it’s get-vm.. Well no, still joking, after that there is get-command, and then there is get-vm . Hehehe ,alright i tried to be funny, and it ended up like always.. As you probably noticed, i have started to put more time into my blog. I am still thinking about how to do many things here, so it will easy for you to find the things you are looking for, and do it as quick as possible. I thought i could introduce a series of posts ‘ get-explanation ‘ where i would be explaining the basics.
If you are pro, i guess there are small chances you will find something revolutionary in them, but still, who knows 😉 We can’t ignore the basics, the fact you know X, doesn’t mean that everybody else knows it, and sometimes it’s just good to revisitthe basics. Since i am already here, writing about the basics, did you know that get-help does not only contain the help for particular commands but also explains the powershell language and things around it as well ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
(Get-Command -Name Get-help).Parameters['Category'].Attributes.ValidValues Alias Cmdlet Provider General FAQ Glossary HelpFile ScriptCommand Function Filter ExternalScript All DefaultHelp DscResource Class Configuration |
We use Get-Command to help us understand how the Get-Help cmdlet works, to be more specific, we try to understand what is behind the ‘Category’ parameter. What i wanted to show you is that there are also ‘books’ / ‘helpfiles’. In my opinion your goal is to be able to find it on your own, hence that above example. One other thing of figuring out that there was a category like HelpFile, is to ask Powershell to tell you this 😉
1 2 3 4 5 6 |
get-help -Category 'sadf' Get-Help: Cannot validate argument on parameter 'Category'. The argument "sadf" does not belong to the set "Alias,Cmdlet,Provider,General,FAQ,Glossary, HelpFile, ScriptCommand,Function,Filter,ExternalScript,All,DefaultHelp,DscResource,Class,Configuration" specified by the ValidateSet attribute. Supply an argument that is in the set and then try the command again. |
If we will make a mistake on purpose in typing, Powershell (people that wrote this cmdlet) is so nice that it suggests us the possible/valid values. You would know now, that there is a category like HelpFile.
From here you would know now that you can read a help about ‘Arrays’, get it ? about_Arrays .. (another failed pun xD). Anyway, you could now read it by using Get-Help -Name about_Arrays
This looks familiar no ? You have this information in your powershell session, but if it’s easier for you to read it online, you can always access this information through your browser https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_arrays?view=powershell-7
Basics
This brings us to the PowerCLI basics, the Get-VM. I mean if you just have installed PowerCLI, i bet the first thing that comes to your mind to test it is
SHOW ME THEM VMS !
This is the beginning and starting point for a lot of administrators that start their journey with PowerCLI. I wanted to write today about this very cmdlet. How can you check yourself what’s going on in Get-vm, or any other cmdlet later on. Let’s have a quick look, the starting point is Get-Help.
You can also open the help via the online docs at VMware Code website:
In regards to the VMware Code website/documentation, you have to be careful what you type in the search box. The top left corner is an input box where you type the command, it’s case sensitive. If you would type gEt-Vm, no results will be given. It’s just something you have be aware.
Let’s start from what we see at the help page:
I have used 4 colors / lines, to get your attention to those lines. They are quite important sections of help. They should ring a bell immediately when you look at any command. That does not ring a bell to you ? Then this paragraph is a must read. I would strongly advise you feel really comfortable with this output. It will help you almost immediately understand what is being required from you in order to run the cmdlet.
ParameterSet
Those are parameter sets. They describe the way how the author of the cmdlets envisioned using / calling it. No, it’s not hard to understand, and it is obvious why it looks sort of like a mini martix to you right now. Author of cmdlet states by them that you can run this cmdlet in 4 different ways. 4 separate ways. Those are unique ways. Author has some expectations about how does one run it. It is being expected from us, to run EXACTLY the way we were asked to in the ParameterSet. You will notice, that i am now reffering to the stuff i wrote about earlier in the post ( i hope you did not cheat, and scrolled down here 😉 ). How do we know how many parametersets are there?
1 2 3 4 5 |
(Get-command -Name Get-VM).ParameterSets.Name Default >>> this is blue color DistributedSwitch >>> green color ById >>> pink color RelatedObject >>> red color |
We clearly see that there are 4 parametersets. We can count them using the .count
1 2 |
(Get-command -Name Get-VM).ParameterSets.Count 4 |
You have to put only those parameters in the command that are part of a single parameter set. You see the redline parameterset ? Ok, it has a parameter called RelatedObject, now look at the purple line, you see the Id parameter. What i am trying to say is that you can’t run this cmdlet using parameters from different parametersets that only exists in their own set. Powershell will not understand which paramterset is being ran. He can tell this by looking at the parameters that are given.
If only RelatedObject would be passed, he would know that oO, watch out this is parameterset ‘RelatedObject’ i will be now running command in way purple.. If you will give him mixed signals by using -RelatedObject and -Id he can’t clearly state which parameterset it is, as 1 parameter comes from the red set, and 1 parameter from pink. There is no (red+pink) set, there is only red AND pink..
Update 1
To clear more on parametersets i made this tiny graphica(please ignore the colors inside, they have nothing to do with the colors from above)
Powershell has to chose the right parameterset. So If you would chose just 1 parameter called ‘name’, would you be able to identify in unique way the right parameterset ? First what comes to you mind is ‘NO’, no because the name parameter exists in two sets, it is used in the ‘default’ and ‘distributedswitch’ parameterset. But but but but , ‘you wrote that i can use Get-vm -name ‘myvmname’
Yes 😉 Welcome to the powershell Neo, lots ahead of us 😉 There is a special cmdletbinding attribute [CmdletBinding(DefaultParameterSetName = ‘ParameterSetName’)] that is helping in those cases. If you have enough parameters in order to run the right parameterset, and it ends up that there are two parametersets to chose from,
your command will go into that parameterset which is marked with DefaultParameterSet. In the case of Get-VM the parameterset name that is default is ‘default’. I know … i know.. it’s bit confusing, but its named like this. It doesn’t have to be named ‘default’ , it can be whatever you want when you will be designing your own cmdlet. So, so when powershell sees that he can use 2 paths , he will go with the one marked as being the default one. I want to show you that default parameterset does not have to be named ‘default’.. Let’s open an example from powershell help
Have a look at the function measure-lines
This is the source, and we clearly see inside that defaultparameterset i pointing to the parameterset ‘Path’, but we also check this on our own:
Again, benefiting from basics, get-help, get-command, your best buddies 😉
Now , the easier bit, so to select proper path for the ‘distributedswitch’ parameterset we have to use some uniqe parmater like virtualswitch:
When virtualswitch parameter is specified, its really easy to tell which parameterset will it be, DisitributedSwitch because its the only parameterset that actually has a parameter called ‘virtualswitch’. Same for relatedobject. I hope this is clear, but if for some reason it’s not , please do leave a comment below the post.
Parameters
You are doing good ! If feeling dizzy, go on fresh air, make tea/coffe. This is very important. I have highlighted in green, pink, red 3 different parameters. The green parameters name is Name, the pink parameter name is Server, the red parameter name is Id. Those are not just some parameters. To the right side of parameter name you can find its object type. The name is a string object, the server is a VIServer object, and Id is String object. String[] <- those brackets next to ‘String’, they mean that it can be 1 String and multiple Strings (more than 1).To exit the shortcuts i should write:
1 2 3 4 5 6 7 8 9 10 |
84|PS> [System.String] IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True String System.Object 92|PS> [VMware.VimAutomation.ViCore.Types.V1.VIServer] IsPublic IsSerial Name BaseType -------- -------- ---- -------- True False VIServer |
Now, let’s get back to the parameters. The green Name is inside [ ] brackets . What does mean if parameters is inside square brackets ? That it is optional, you can use it, but you don’t have to use it. [ -param <type>] now, what does mean if there are not any square brackets around the parameter ? Well, you guessed it, the opposite, meaning this is MANDATORY parameter and you have to use it. The green name is bit specific, inside the square brackets there is [-Name] …
Parameter inception…
It means that the parameter name is optional, meaning you do not have to use the -name for the parameter. I know it sounds crazy but bear with me. This implies that the parameter is positional, powershell will understand that you are submitting him VMNameABC as parameter name, because he EXPECTS it to be on the first position. How come i know it expects it on first position ? 1 – because its on the most left side in the command syntax, and 2 –
1 2 3 4 5 6 7 8 9 10 11 12 13 |
95|PS> (get-command get-vm).ParameterSets[0].Parameters[0] Name : Name ParameterType : System.String[] IsMandatory : False IsDynamic : False Position : 0 ValueFromPipeline : False ValueFromPipelineByPropertyName : False ValueFromRemainingArguments : False HelpMessage : Aliases : {} Attributes : {False, False, S |
because it is being reported with ‘Position 0’. Let me show this :
1 2 3 4 5 |
29|PS> Get-VM -Name 'centos' Name PowerState Num CPUs MemoryGB ---- ---------- -------- -------- centos PoweredOff 1 2,000 |
This is quite clear, we gave the parameter Name value of a string ‘centos’. In return get-vm has returned us a ??? something ??? that looks like our vm and we see there centos in name. This is for later but for now you should understand that we have received a virtual machine object :
1 2 3 4 5 6 7 8 9 |
31|PS> (Get-VM -Name 'centos').gettype().fullname VMware.VimAutomation.ViCore.Impl.V1.VM.UniversalVirtualMachineImpl [C:\] 32|PS> (Get-VM -Name 'centos').gettype() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True False UniversalVirtualMachineImpl VMware.VimAutomation.ViCore.Impl.V1. |
Alright, now let me explain whats with the positional thingy. It simply means that if i put it to position 0 (first position after cmd) it will get treated as the parameter ‘Name’ , and its treated like the name parameter now because you are telling him : look its a -Name ‘XyZ’ , but : look , its on the first position, so this is the name ‘ZyZ’
1 2 3 4 5 |
35|PS> Get-VM 'centos' Name PowerState Num CPUs MemoryGB ---- ---------- -------- -------- centos PoweredOff 1 2,000 |
See ? we just wrote ‘centos’ and he understood that we gave him the value for ‘Name’ parameter. Let’s try see what happens if we will do what we were not supposed to do, mix the parameters from different parametersets.
1 2 3 |
37|PS> Get-VM -Name 'centos' -id 'VirtualMachine-vm-70' Get-VM: Parameter set cannot be resolved using the specified named parameters. One or more parameters iss ued cannot be used together or an insufficient number of parameters were provided. |
He refuses to run it, because there is no clear way for him to pick the right parameterset.
Let’s have a look at the highlighted in red ‘Id’ parameter. You noticed that it has no square brackets around the entire parameter, nor it has any square brackets around his param name. This means that you can’t skip it, you can’t not use the parameter name
1 2 |
39|PS> Get-VM 'VirtualMachine-vm-70' Get-VM: 04/07/2020 19:16:54 Get-VM VM with name 'VirtualMachine-vm-70' was not found using the specified filter(s). |
That’s right, you guess it, i tried to give him the VM id , but thought i am giving him the name of the virtual machine which would be equal to ‘VirtualMachine-vm-70’. That’s the reason why you can’t omit the -Id param, otherwise it would be not possible to understand what do you mean by this.
1 2 3 4 5 |
40|PS> Get-VM -id 'VirtualMachine-vm-70' Name PowerState Num CPUs MemoryGB ---- ---------- -------- -------- centos PoweredOff 1 2,000 |
If you give him now properly the value for id , he returns us the VM object. To recap, parameters can be positional, mandatory, they are of a special type. You can read more about them in .. YES !! that’s righ in get-help -name about_parameters or using online version https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_parameters?view=powershell-7 .
Get-VM parameter : Server
You will see this basically a lot when working with PowerCLI cmdlets. What can we learn on our own about the server param ? Let’s have a look:
Is it named paramater that has no default value and it’s not required for you to type it. It does not mean its not being used in behind the scenes. If you will not specify the -server parameter, it will be used according to your current configuration from Get-PowerCLIConfiguration
1 2 |
PS C:\> ((Get-PowerCLIConfiguration)|?{$_.Scope -eq 'Session'}).DefaultVIServerMode Multiple |
There can be Single or Multiple. When in single, the -Server parameter will get default to $global:defaultVIServer , when in Multiple, it will utilize the $global:defaultVIServers (plural). In single mode, when you will connect first to virtual center ‘vcA’, then you will connect to ‘vcB’, and after that you will conenct to ‘vcC’, at the moment if you would issue ‘get-vm’ if you use the last virtual center to which you have connected. It would be vcC. When in multiple mode, you would be storing your virtual center servers in an array, and the get-vm would submitted to all of the virtual centers, meaning you would get vms from vcA, vcB, vcC
This is something you have to be careful with, and always remember. Most people do not specify the -Server parameter, as i believe this is not natural when typing the command. I mean, why on earth would i specify the server parameter if i am just connected to my 1 virtual center, i just got 1 virtual center. Right, but please remember that besides ‘tiny labs’ this product is also ran in enterprises where you can multiple virtual centers connected in SSO domain, and they are big… BIG , PHAT, CHONKY, you know.. like my cat roger … look at this beautiful chonk
Now this was some introduction
Alright , i hope you are alive and kicking, and ready for the get-vm part now 😉 Why this long introduction ? It’s just simply crucial later on to understand what you will be dealing with. We can obtain virtual machines from the virtual center in 4 ways( parametersets).
First one is by simply giving to the cmdlet the VM name/s, Datastore on which they reside, Location where they are, the TAG they got marked with. On top of that in case they are in some container you can chose not to get recursive with things.
If you have a Folder in which you look for vms, that contains more folders inside with even more vms (in which you have no interest seeing) you can use the -NoRecursion switch. You notice what i just wrote ? ‘Switch’, i used this word because the parameter type is a ‘Switch’ , it can either be on or off ,like a switch 😉 If you would use it in your cmdlet by typing -SomeSwitch , it will get set to ON, as it’s true that its there. If you would not mention it, it’s set to off as its not there. You can also be really explicit and just state -Someswitch:$True or -SomeSwitch:$False ( in this case you explicitly pointing out that it has to become not true – false.
Let’s obtain our vms from TestFolder
How come we see 2 vms? Well, that’s because we are asking to obtain ALL vms that are in folder TestFolder and any other folderds down the path. What you did not see is that inside the ‘DontLookHere’ i also squeezed 1 vm.
So in order to get only the ‘vrealizelcm’ vm, we would have to use the switch parameter called ‘NoRecursion’.
Much better. But stil.. not explained entirely. Let’s EXPLAIN !!! What’s with the Location thingy ? How come this worked, i could just put a name of a folder there ? What is there to help us ? GET-HELP
1 2 3 4 5 6 7 8 9 10 11 |
52|PS> get-help get-vm -param location -Location <VIContainer[]> Specifies vSphere container objects you want to search for virtual machines. Supported container object types are: ResourcePool, VApp, VMHost, Folder, Cluster, Datacenter. Required? false Position? named Default value None Accept pipeline input? True (ByValue) Accept wildcard characters? true |
So what does this all mean ? <type>, remember ? so this magic VIContainer is a type, so objects of this type can be passed to the -Location parameter. VMware PowerCLI team did a great job, and also provided us some documentation for the parameter, and we know that this supports a Folder (blue/yellow), Cluster, Datacenter and so on. I saw people (including me as well) using it for example like :
1 |
get-datacenter | get-folder 'TestFolder' |Get-VM |
But by now, you know that this can be written easier, by passing to the Location paramter the folder name.
MORE !!! MORE EXPLANATION !!!
Okey, so how come we could put a folder inside the -Location parameter ?The type for Location is VIContainer, so we can lookup the folder on our own and that type is not the VIContainer.
1 2 3 4 5 6 7 8 9 10 |
58|PS> (Get-folder 'TestFolder').Gettype() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True False FolderImpl VMware.VimAutomation.ViCore.Impl.V1.Inventor [C:\] [20,50 m 59|PS> (Get-folder 'TestFolder').Gettype().FullName VMware.VimAutomation.ViCore.Impl.V1.Inventory.FolderImpl |
Magic… Definitely MAGIC . So, this is because it implements the VIContainer interface
1 2 3 4 5 6 7 8 9 10 11 |
(Get-folder 'TestFolder').Gettype() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True False FolderImpl VMware.VimAutomation.ViCore.Impl.V1.Inventory.InventoryItemImpl (Get-folder 'TestFolder').Gettype().ImplementedInterfaces |? {$_.Name -contains 'VIContainer'} IsPublic IsSerial Name BaseType -------- -------- ---- -------- True False VIContainer |
We checked the Folder type, and it’s compatible with the VIContainer. Last way from the default parameterset is to obtain VMs from the particular datastore/ds clusters but using the -Datastore parameter. We can check it with get-help. You will see that we can pass not 1 datastore, but more , because of StorageResource[] <- 1 or more (Array)
Not only you can just type the name of your datastore
but since it is accepting pipeline input we can throw the datastore object from the left side via the pipe on it.
What about the fact that we can pass the datastore the parameter -Datastore using a string instead of the real datastore object ? It’s about OBN transformations described more in details here : https://pubs.vmware.com/vsphere-51/index.jsp?topic=%2Fcom.vmware.powercli.cmdletref.doc%2Fabout_obn.html . The OBN feature will transform our text into the right object. This is also valid for many other parameters, not only the datastore (I mean PowerCLI cmdlets/parameters).
1 2 3 4 5 6 7 8 9 |
133|PS> (Get-Command Get-VM).Parameters['DataStore'].Attributes[2] Critical : True ContextPrincipalName : ContextOptional : False ContextRelationName : TargetTypeList : {VMware.VimAutomation.ViCore.Types.V1.DatastoreManagement.Datastore, VMware.VimAutomation.ViCore.Types.V1.DatastoreManagement.DatastoreCluster} TransformNullOptionalParameters : True TypeId : VMware.VimAutomation.Sdk.Util10Ps.BaseCmdlet.ObnArgumentTransformationAttribute |
As you can see above, we know that the Datastore parameter can get transformed into either a Datastore, or DatastoreCluster.
To make this more clear you should have a look about Argument Transformation Attribute. To give you some quick / brief impression of how it would work, have a look at the below script i wrote. Test-VMPowerState function job is to write to the host if the VM is poweredoff or poweredOn for example. This function takes 1 parameter (obj) which is a VM, and a VM might be a real Virtual Machine object that we already pulled using a Get-VM, or it could be just a plain String (that would pointing to vm name), or a view, or a something that is being returned by get-viobjectbyviview (VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl). Below is some tiny implementation of this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
using namespace System.Management.Automation class VMNameTransformationAttribute : ArgumentTransformationAttribute { [Object] Transform( [EngineIntrinsics]$engineIntrinsics, [Object]$inputData ) { $vmname = $inputdata if ($InputData -is [String]) { if ($vmr = get-vm -Name $vmname) { write-host "i have seen a VM as a text thingy" return $vmr } else { throw 'Cant aquire the VM' } } elseif ($inputData -is [VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl]) { write-host "i have seen a GetVIObjectByView thingy" return $inputData } elseif ($inputData -is [VMware.VimAutomation.ViCore.Impl.V1.VM.UniversalVirtualMachineImpl]) { write-host "i have seen a get-vm VM thingy" return $inputData } elseif ($inputData -is [VMware.Vim.VirtualMachine]) { write-host "i have seen a get-view VM view thingy" return Get-VIObjectByVIView -VIView $inputData } else { throw 'Unexpected object format' } } } function Test-VMPowerState { param ( [VMNameTransformationAttribute()][VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine]$obj ) Write-Host "VM is $($obj.PowerState)" } |
So my parameter is fine if fed with text, vm, view, the ‘other almost vm’ types.
ByID
So the parameterset ByID is nice and easy it expects us to provide a string for parameter ID. What is an ID ? it’s a unique label for your entity in VirtualCenter , the VM has a Name and MoRef ID (Managed Object Referece). Let’s not get into details right now 😉 All you need to know, is that that there can be 10 virtual machines with the same nam of ‘MyVM’ but just 1 VM with id of ‘VirtualMachine-vm-128. You need to know the ID in first place, so let’s obtain it:
1 2 3 4 5 |
142|PS> Get-VM -Name 'vc01' | SElect-Object NAme,Id Name Id ---- -- vc01 VirtualMachine-vm-68 |
Alright , so now we can call it like:
1 2 3 4 5 |
143|PS> Get-VM -id 'VirtualMachine-vm-68' Name PowerState Num CPUs MemoryGB ---- ---------- -------- -------- vc01 PoweredOff 2 10,000 |
Third parameterset contains the Tag/VirtualSwitch/Name , for example if we would want to find only those VMs which are tagged with tag: ‘TestTag’
Check vms which are connected to a distributed switch using the -VirtualSwitch parameter
You can wonder why the parameterset allows us to select not only the Tag/Switch but also a name ? Well, that’s because you might wanted to ask for VMs that belong to a TAG, but from that set you just want a particular one with a special name.
There is nothing wrong i guess if you would just obtain all the vms from TAG ‘TestTag’ and they filter it on your end with a Where-Object cmdlet. Important thing that you need to know at this moment is that , the more thing you filter on API/Server side, the faster the cmdlet will process. There is no need to download all the objects to compare their names on your computer in your powershell session, let your virtual center do this for you.
Last but not least – RelatedObject
1 2 3 4 5 6 7 8 9 10 11 |
153|PS> get-help get-vm -Parameter RelatedObject -RelatedObject <VmRelatedObjectBase[]> Specifies objects to retrieve one or more vSphere VirtualMachine objects that are related to them. This parameter accepts vCloud CIVM and OMResource objects. Required? true Position? named Default value None Accept pipeline input? True (ByValue) Accept wildcard characters? false |
The whole idea here is that , there are some objects that relate to yours in some way. Because they relate, you can obtain your VM but looking at the relation between them. Let’s say that you want to get a VirtualMachine that relate to a virtual port group from some virtual distributed switch
1 2 3 4 5 6 7 8 |
162|PS> $DVSwitchPort = Get-VDPortgroup -Name 'TestPort1' [C:\] 163|PS> get-vm -RelatedObject $DVSwitchPort Name PowerState Num CPUs MemoryGB ---- ---------- -------- -------- vrealizelcm PoweredOff 2 6,000 |
The virtual portgroup imeplements the interface VMRelatedObjectBase
It will fit without any issues for the -RelatedObject parameter. There is no OBN happening for RelatedObject parameter, so don’t try to give it a value of for example ‘name of the portgroup’, etc..
As it will fail
1 2 |
186|PS> get-vm -RelatedObject 'TestPort1' Get-VM: Cannot bind parameter 'RelatedObject'. Cannot convert the "TestPort1" value of type "System.String" to type "VMware.VimAutomation.ViCore.Types.V1.RelatedObject.VmRelatedObjectBase". |
Get-VM examples
Always remember about virtualmachines that can have the same name.
1 2 3 |
PS C:\> (get-vm -Name 'vrealizelcm').name vrealizelcm vrealizelcm |
This is not a glitch in the matrix, there are 2 VMs with name ‘vrealizelcm’. I know, shocking…
In order to have vms with the same name, you have to separate them with some container. You can’t create a VMs with the same name in the same container.
1 2 3 4 5 6 |
PS C:\> (get-vm -Name 'vrealizelcm').folder Name Type ---- ---- TestFolder VM DontLookHere VM |
Those two vms are in different folders, lets try to create another ‘vrealizelcm’ vm inside the ‘DontLookHere’ folder:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
PS C:\> $DontLookHereFolder = Get-Folder -Name 'DontLookHere' PS C:\> $DontLookHereFolder Name Type ---- ---- DontLookHere VM PS C:\> New-VM -Name 'vrealizelcm' -VMHost 'host1.greg.labs' -Location $DontLookHereFolder -Datastore 'DSPrzedpokoj' -DiskMB 128 -MemoryMB 128 -NumCpu 1 New-VM : 7/5/2020 9:59:47 AM New-VM VM or template with name 'vrealizelcm' already exists. At line:1 char:1 + New-VM -Name 'vrealizelcm' -VMHost 'host1.greg.labs' -Location $DontL ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidArgument: (:) [New-VM], DuplicateName + FullyQualifiedErrorId : Client20_VMServiceImpl_TryValidateUniqieVmName_DuplicateName,VMware.VimAutomation.ViCore.Cmdlets.Commands.NewVM |
Let’s create another folder inside the ‘DontlookHereFolder’.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
PS C:\> New-Folder -Name 'AnotherSubfolder' -Location $DontLookHereFolder Name Type ---- ---- AnotherSubfolder VM PS C:\> $anotherSubFolder = get-folder 'AnotherSubFolder' PS C:\> $anotherSubFolder Name Type ---- ---- AnotherSubfolder VM PS C:\> New-VM -Name 'vrealizelcm' -VMHost 'host1.greg.labs' -Location $anotherSubFolder -Datastore 'DSPrzedpokoj' -DiskMB 128 -MemoryMB 128 -NumCpu 1 Name PowerState Num CPUs MemoryGB ---- ---------- -------- -------- vrealizelcm PoweredOff 1 0.125 PS C:\> get-vm -Name 'vrealizelcm' Name PowerState Num CPUs MemoryGB ---- ---------- -------- -------- vrealizelcm PoweredOff 2 6.000 vrealizelcm PoweredOff 1 1.000 vrealizelcm PoweredOff 1 0.125 |
There we have it, 3 vms with name ‘vrealizelcm’. Can you imagine what would happen if you would do get-vm -name ‘vrealizelcm’ |remove-vm ? Instead of deleting 1 vm, you would get rid of 3 vms. Bummer… well , thank god that the remove-vm has a prevention system, that asks you if you really want to do it (ConfirmImpact) that is set to high, you would be asked 3 times if you are really sure. If you would not know that you had 3 vms of the same name, you might just think that ‘ahh another, glitch in the matrix’, i had to press 3 times yes 😉 hehe.
Let’s get some more information about the vms. The information is already there, we just don’t see it, but it’s there. Have a look:
1 2 3 4 5 |
PS C:\> $myvm Name PowerState Num CPUs MemoryGB ---- ---------- -------- -------- win10g PoweredOn 2 4.000 |
So we know the name of the vm, the powerstate , amount of cpus, and memory in GB. Is that all ? No. This is just default displaying behavior, you will see 4 columns/properties.
In case you want to understand why do you see columns like this. for example if you ever wondered why there is displayed here column ‘Num CPUs’ , but when you would list all the VM properties you would not find anything like this ? Here is the explanation:
Our VM type has a format for displaying the object that states that Name,PowerState, Num CPUs, MemoryGB will be displayed when displaying the VM object. Values coming from Name,PowerState,NumCPU, “{0:N3}” -f $_.MemoryGB will be used for providing the data. (That par with the memory string format, you dont see on the picture, but it is there).
Might be handy to read later as well:
Ok, remember what i wrote in the begging ? That bla bla bla ‘something’ that looks like vm ? Ok, lets inspect this something. This is actually a Virtual Machine object. It’s time to meet our new best buddies, .gettype(), get-member . In the picture below you see ‘gm’ which is an alias of ‘get-member’, a lot of people write gm instead of get-member, please have this in mind.
Those are the properties of the
1 2 |
PS C:\> $myvm.gettype().fullname VMware.VimAutomation.ViCore.Impl.V1.VM.UniversalVirtualMachineImpl |
Virtual machine type. You check the type by invoking method ‘gettype()’ on an object. Since my virtual machine object is now inside a variable $myvm i can call the methods on it.Now you see that there are way more properties inside our received Virtual Machine object. What is the fastest, easiest way to show them on the screen ? Using a format-list .
Now you should connect the dots, and think : ahh.. that explains why there is just 4 colums when displaying the $myvm, otherwise it would not be readable if we would have to squeeze so many columns. Later on i will show you how to chose the right set of properties you want. For the really curious ones, ‘hey, but that’s not enough of information!, need more, more more more’, have a peek what is inside the ‘ExtensionData’ 😉 Ohh boy.. another rabbit hole.
If you don’t remember full name for a vm name, datastore name, whatever name, you can use a wildcard get-vm -Name ‘*10*’ That way all vm with names that match anything_10_anything will be returned. I want also to show you something since we are now talking about wildcards. * is a wildcard, so is a ? . Let’s say i have a virtual machine called greg in square brackets, like so:
Ok, let’s fetch this one. So…
Nope, that did not go well. That’s because, what i forgot to tell you, and that’s what a lot of people forget is that a [ and ] are also wildcards. [set_of_characters_that_can_match] . So for example
Now, if you will ever have to get the [name], you will have to escape the wildcard characters with ` a backtick or double backtick for double quotes, so :
Summary
Ahh yess… now we understand what’s what. So nice.. sooo fluffy.
That being said… I mean yeah well.. Seriously that’s lots of stuff happening here. I bet you expected something more like ‘Ohh you know, its easy, you just get-vm myvm, and bob’s your uncle’ … but no… 😉 When i started to spend more and more time with powershell, i just had to understand why sometimes things that i try to run fail… This was showing me how little i knew, and i still probably don’t know. .
I hope i explained it for you , i tried to be as precise as i could, if by any chance i left something not clear, please do leave a comment and let me know. I really want to make others understand this, i am not writing it just to write, for myself (i mean partially yes – as i also learn more while writing it ). Please remember, there are no stupid questions etc, i was rushing at the end, i will probably make few more review of this, For now , that will be all.
Big thanks
go to Chris Dent, for being so supportive and helping me out with explaining some powershell quirks, without him i would not be able to explain this is such a great detail.
1 comment
This is brilliant blog entry. Wish that more bloggers would describe “basics” like you’ve just did. Looking forward for more content for beginners from your end and thank you for your hard work!