Before we proceed … When you post code, sample data, console output or error messages please format it as code using the preformatted text button ( </> ). Simply place your cursor on an empty line, click the button and paste your code.
Really? Since it is pretty unlikely that you will find something exactly fitting your needs you should try to find something what’s close enough to your needs to be adapted easily.
Regardless of that - I would recommend not to mix information about the host and the VMs in one table as some of the information would be redundand for the hosts and actually useless for the VMs.
What does it output? How do you think you could change the command to output more than just what it does now?
ComputerName Name Id Notes State NetworkAdapters
---- --
New-vm c1 8b89c96-d5a5-4c61-b63c-232d2133f192 Running {Network Card}
Boulbul test1 81de770f-54cb-4d1a-beed-097e0cc1155a Running {Network Card}
Boulbul test2 83551f8f-59e3-4681-bf5d-0f76c940a333 Off {Network Card}
As you can see, it does not show the network card details, but just the text "Network Card instead.
What I would like to add, is add to the result above IPv4, IPv6, Interface Name & MAC of the VM to this output.
This command launched from within the vm:
(get-vm).NetworkAdapters
Will yield:
Name IsManagementOs VMName SwitchName MacAddress Status IPAddresses
---- -------------- ------ ---------- ---------- ------ -----------
Carte réseau False Nouvel ordinateur virtuel 00155D6A2A06 {Ok} {}
Carte réseau False test1 Prive 00155D6A2A03 {Ok} {169.254.12.49, fe80::d13c:2319:ac06...
Carte réseau False test2 Prive 00155D6A2A04 {}
But, I need to associate this output with the one above (invoke command) in order to the get the this intended result:
ComputerName Name Id Notes State IPAddresses MacAddress
---- --
Boulbul test1 81de770f-54cb-4d1a-beed-097e0cc1155a Running 169.254.12.49 fe80::d13c:2319:ac06
It does not just show the text “Network Card” it shows this in curly braces - that’s the actual interesting point on this output. Curly braces indicate that the property shown is an array. Even if there’s just one element in it what seems to be the case in your case.
The most common ways to combine the properties of the elements of those subarrays with the properies of the outer elements are ether calculated properties or nested loops combined with a “[PSCustomObject]”. Since I like the syntax of a [PSCustomObject] more I’ll show this:
Get-VM |
ForEach-Object {
$VM = $_ # this variable assignment makes the current pipeline object available inside the nested loop
$NicList = $_.NetworkAdapters
foreach ($Nic in $NicList) {
[PSCustomObject]@{
ComputerName = $VM.ComputerName
VM_Name = $VM.Name
VM_State = $VM.State
Nic_Name = $Nic.Name
Nic_MacAddress = $Nic.MacAddress
Nic_IPAddresses = $Nic.IPAddresses
}
}
}
I need the Guest and Host Operating System. I could not find any way with Get-VM
I found a script which does this…
#Script get Operating System.
#show all properties for reference only
(Get-WMIObject win32_operatingsystem) | select *
#retrieve OS
$OS1 = (Get-WMIObject win32_operatingsystem).caption
#write it out
write-host $OS1
However, combining the 2 together was a night mare.
List item
The Format-table does not display all output on the screen. I have even tried to redirect the ouput onto an excel file, but I got the same result.
Is there anyway to keep the table format and get all the output on the csv/excel file?
Why that? And why is it not shown in the code you posted? You simply have to put it in front of the [PSCustomObject].
Format cmdlets in general are meant to be used for display purposses in the console only. And they have limits. With more than 10 properties to show it does not make that much sense to display that in a console anyway. … unless you have a very very wide screen.
That’s the worst idea ever. Format cmdlets destroy the powerful and rich objects and produce stupid boring pixels on the screen. Their output is not meant to be piped anywhere.
Instead you can pipe the output directly to Export-Csv or - if you install the great module from Doug Finke ImportExcel - to Export-Excel what results in a proper already formatted Excel sheet.
Hi, Thank you once again…Your advice worked with a charm … the [PSCustomObject] was so simple to use… I know understands much better the use of this command…I have managed to export all output via the module exportExcel, however…All output from the variable “Nic_IPAddresses” , “VM_HD_Size” & " VM_HD_Location" are ether empty or have a value of “stem.string” in them.
Here is the Code:
Get-VM |
ForEach-Object {
$VM = $_ # this variable assignment makes the current pipeline object available inside the nested loop
$NicList = $_.NetworkAdapters
foreach ($Nic in $NicList) {
[PSCustomObject]@{
ComputerName = $VM.ComputerName
Host_OS = (Get-WMIObject win32_operatingsystem).caption #|Select "Local Area Connection* 1"
Host_IP = (Get-NetAdapter )
#Host_IP = (Get-NetIPAddress -AddressFamily IPv4 -InterfaceAlias "Local Area Connection* 1" |select -Property IPAddress)
Nic_IPAddresses = $Nic.IPAddresses
VM_Name = $VM.Name
Nic_MacAddress = $Nic.MacAddress
VM_CreationTime = $VM.CreationTime
VM_MemoryAssigned = $VM.MemoryAssigned # to write in MB
VM_ID = $VM.VMId
VM_HD_Size = $VM.VMId |Get-VHD| select Size , {$_.Size /1GB} # to filter this output in order to get just VM_HD_Location
VM_State = $VM.State
Nic_Name = $Nic.Name
VM_HD_Location = $VM.VMId |Get-VHD | Select Path # to filter this output in order to get just VM_HD_Location
}
}
} | Export-Excel -Path C:\temp\allvms.xls
Here are both output from the script and redirection onto the excel file.
There is always a way. But it depends on the existing conditions. If your VMs ALWAYS have only one IPv4 and one IPv6 address on their NICs you could do something like this:
I now realized that it was tedious to include the host IP addresses in the script, knowing that each server would have many interfaces with different IP addresses. I will leave this task for the end.
I ran the script on some servers instead of my workstation (test platform). Although the OS is the same on all servers, I got a different result on a few!
With the VM_HD_Size, I get an error related to “Op_Devision”. Although there is an error, the script manages to get the data and write it to the Excel file on some servers, but not on others…It also moves duplicates IPv4 on both Nic_IPAddressesV4, Nic_IPAddressesV6 fields.
For the VM_HD_Location it works fine, but it adds other columns in the excel file which are not really needed. Is there anyway retrieve only the disk location please?
You will also notice in the picture of excel output (next post) that on some cells I got “System.Collections.ArrayList” value instead of the disk location!
Here is the code:
#https://www.powershellgallery.com/packages/ImportExcel/7.8.0
Install-Module -Name ImportExcel
#forum
Invoke-Command -ComputerName SRV1,SRV2 -Credential boulbul -ScriptBlock {
Get-VM |
ForEach-Object {
$VM = $_ # this variable assignment makes the current pipeline object available inside the nested loop
$NicList = $_.NetworkAdapters
$VM_HD = $VM.VMId | Get-VHD
foreach ($Nic in $NicList) {
[PSCustomObject]@{
ComputerName = $VM.ComputerName
Host_OS = (Get-WMIObject win32_operatingsystem).caption #|Select "Local Area Connection* 1"
Nic_IPAddressesV4 = $Nic.IPAddresses[0]
Nic_IPAddressesV6 = $Nic.IPAddresses[1]
#Nic_AllIPadresses = $Nic.IPAddresses -join ', '
VM_Name = $VM.Name
Nic_MacAddress = $Nic.MacAddress
VM_CreationTime = $VM.CreationTime
VM_MemoryAssigned = ($VM.MemoryAssigned / 1GB)# to write in MB
VM_ID = $VM.VMId
VM_HD_Size = ($VM_HD.Size / 1GB)
VM_Status = $VM.Status
VM_HD_Location = $VM_HD.Parent[1] # to filter this output in order to get just VM_HD_Location
}
}
} #| Export-Excel -Path C:\temp\allvms.xls
# Export the output to a CSV file. Change the file path accordingly.
} | Export-Excel -Path C:\temp\allVM.xls
Would it be possible to have the VM operating system, and the VM Operating System Name? Please give me hint? Thank you, and my apologies for the many questions
Hmmm … actually you’re not querying the host IP addresses. At least not with the code you shared so far. But each VM can have multiple NICs as well and every single NIC can have multiple IPv4 and / or IPv6 addresses. You will have to make a decission what and how to display this in your data. You are actually trying to show hierarchical data in a structrured representation.
The way you did is wrong. You querying the OS of the computer the script runs on. That’s why you get the same result again and again.
Again - you should always read the help for the cmdlets you’re about to use … completely incuding the examples.
Instead of Get-WmiObject you should use
Example 7 shows how to query a remote computer. And the query should be outside of the inner loop.
Please do not post images of code or error messages or console output. Instead post the plain text and format it as code.
The extra columns are not from the VHD_Location. They are from the remote execution in general. When you read the help for
you can see that you can hide the computername with the parameter -HideComputerName
If you have more than one VHD connected to a VM you have to either use another nested loop or concatenate the VHDs to one data cell to be shown correctly in your Excel sheet.
Again - you’re trying to show hierarchical data in a structured manner!!!
Yes. BUT that’s going to be a little more complex the way you do it right now.
You are already running this script block against a remote computer. So you cannot remote into the next computer from inside of this script block. But you could use the result of this query as a source for a CIM query against all VMs directly outside of the first script block.
I will perform some tests today and will get back to you…meanwhile, on another project, I have a number of clusters, on each cluster there are VMs hosted on a number of Nodes…I need to get the same result as above…with the exception of the loop to the clusters, would there be heavy modification to the script above?
I actually run the code with nvoke-Command -ComputerName SRV1,SRV2... ; would not Get-WmiObject command run on each Hypervisor “SRV1,SRV2” instead of the machine I am running from the script?
Blockquote
It worked well…thank you.
does that mean that I have to run it with the invok ommand from the host server just like this?
I have tried running it directly after the above code and with inoke command, but did not work either way.
With the invoke command I got nothing on the output.
Without the invoke command I got the following:
Get-CimInstance : WinRM cannot process the request. The following error occurred while using Kerberos authentication: Cannot find the computer Win10-2022-01. Verify that the computer exists on the network and that the name provided is spelled
correctly.
At line:35 char:11
+ $OS = Get-CimInstance -ClassName CIM_OperatingSystem -ComputerNam ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (root\cimv2:CIM_OperatingSystem:String) [Get-CimInstance], CimException
+ FullyQualifiedErrorId : HRESULT 0x80070035,Microsoft.Management.Infrastructure.CimCmdlets.GetCimInstanceCommand
+ PSComputerName : Win10-2022-01
You’re right. My mistake. Sorry. I had still the initial version in mind where you run the code from the local machine.
Anyway - you should move this query out of the inner loop to not query this information several times. And you should not use Get-WmiObject anymore.
Cool.
No. That wouldn’t work. You cannot run a command on a remote computer and remote from there to a third computer. That’s called double hop and it is not allowed by default.
Since you use Get-CimInstance and its built in abilty to query remote computers you should run this code from the local computer you use to run the other code. … so without Invoke-Command and the script block.
Some of your VMs may not run. So you need to determine before querying if they’re online or not. You can use an if condition with Test-Connection in advance.
What I cannot understand is that all the VMs are working and I am getting the same errors as above for all of them. what is even more confusing, is that the VM value points to the VM’ name and not the VM’ Operating System Name… Please refer to the following output again (My apoligies, I have not entered the correct output above, this is the right one)…
Get-CimInstance : WS-Management could not connect to the specified destination: (Microsoft Windows Server 2019 Standard:5985).
At line:41 char:11
+ $OS = Get-CimInstance -ClassName CIM_OperatingSystem -ComputerNam ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (root\cimv2:CIM_OperatingSystem:String) [Get-CimInstance], CimException
+ FullyQualifiedErrorId : HRESULT 0x80072ee5,Microsoft.Management.Infrastructure.CimCmdlets.GetCimInstanceCommand
+ PSComputerName : Microsoft Windows Server 2019 Standard
VM : Win10-2022-01
VM_OS :
See…under VM it is reffering to the VM name and not its operating system name …cause the name under the OS is different, and it should have someting else…unless I have badly explained myself in my request? and there is no value under VM_OS? any hints please.
To debug your code you run it line by line and just for one VM and inspect the output in the console. If the code works as needed for one computer you take the next step and so on.
Of course. The name of the VM comes from the input data and is available. The OS comes from the query inside the loop. And because that query does not work you don’t have a result. Logic, isn’t it?
I got the same result as above when I run it from a management server.
Running it from the hypervisor directly yelded the following:
Get-CimInstance : WinRM cannot process the request. The following error with errorcode 0x8009030e occurred while using Kerberos authentication: A specified logon session does not exist. It may already have been
terminated.
Possible causes are:
-The user name or password specified are invalid.
-Kerberos is used when no authentication method and no user name are specified.
-Kerberos accepts domain user names, but not local user names.
-The Service Principal Name (SPN) for the remote computer name and port does not exist.
-The client and remote computers are in different domains and there is no trust between the two domains.
After checking for the above issues, try the following:
-Check the Event Viewer for events related to authentication.
-Change the authentication method; add the destination computer to the WinRM TrustedHosts configuration setting or use HTTPS transport.
Note that computers in the TrustedHosts list might not be authenticated.
-For more information about WinRM configuration, run the following command: winrm help config.
At line:2 char:7
+ $OS = Get-CimInstance -ClassName CIM_OperatingSystem -ComputerName $V ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (root\cimv2:CIM_OperatingSystem:String) [Get-CimInstance], CimException
+ FullyQualifiedErrorId : HRESULT 0x80070520,Microsoft.Management.Infrastructure.CimCmdlets.GetCimInstanceCommand
+ PSComputerName : Win10-2022-01
Just to let you know that the credentials to access the hypervisor is not the same as the once for the VM…wouldn’t this cause any problem? but then I thought that VMs can communicate some information directly without the need have credentials?
I will try to be clearer here… Each computer has a name ( this is what I refer to by the OS name). And each VM has a name too.
Your code managed to get the VM name with no probme (Win10-2022-01)…What I also asked for is for the name that was given to the VM (E.g: Boulbul) when installing the operating system.
If you think that it hard to do, let’s not worry about it…Thank you so much for your help.
Ahhhh … now I see … … that adds another complexity layer on top of the already existing ones.
I think a better name for OS name would be hostname. OS name usually would be “Windows Server 2019” or something like this.
I actually never worked with an environment like this. All our servers have the same hostname like their VM.
Of course you need to use the hostnames of the VMs to access them with Get-CimInstance and not the VM names. You could try to resolve the IP addresses you determined with the query before to the according hostnames and use these for the further steps.
And of course you need to have sufficient rights to access the target computers with Get-CimInstance.
Thank you Olaf, I will stop here for this request… …OOOH., how can I forget the “hostname”… …I think that this would be more than enough…You assistance was great, and would not have been possible to get to this stage without your aid.
This is the final code for those who find it usefull
Olaf, I have another request that is related to clusters…I will search first if I cannot find the answer, I will post it onto another post if you don’t mind.