How to Get Actual Hard Disk Memory of A VM? - powershell

Is it possible to get the actual hard disk usage of a virtual machine?
Measure-VM -Name * | select-object -property TotalDiskAllocation
The TotalDiskAllocation property gets the total disk space assigned to the VM and even though this is helpful I also need to know how much is really being used.
For example, if a VM has 150 GB of allocated memory and it only uses 50 GB, is there any Powershell command that will be able to extract the 50 GB? If yes, how will I be able to incorporate that script to the script above?

Based on your attempt to use Measure-VM, I assumed you are using Hyper-V. I use something similar to this in one of my Hyper-V scripts:
(Get-VM dechiro1).HardDrives | ForEach {
$GetVhd = Get-VHD -Path $_.Path
[pscustomobject]#{
Name = $_.Name
Type = $GetVhd.VhdType
ProvisionedGB = ($GetVhd.Size / 1GB)
CommittedGB = ($GetVhd.FileSize / 1GB)
}
}
Basically, for each of the virtual machine's hard drives, use Get-VHD to get the VHD details which includes the full size and what I refer to as the committed size (actual space on disk).
Example output:
Name Type ProvisionedGB CommittedGB
---- ---- ------------- -----------
Hard Drive on IDE controll... Dynamic 20 0.00390625
Hard Drive on IDE controll... Dynamic 40 0.00390625
Edit:
If you wanted to pull from every VM and include the VM name with the returned object and you prefer to use the pipeline form, this will work:
Get-VM | ForEach { $Vm = $_; $_.HardDrives } | ForEach {
$GetVhd = Get-VHD -Path $_.Path
[pscustomobject]#{
Vm = $Vm.Name
Name = $_.Name
Type = $GetVhd.VhdType
ProvisionedGB = ($GetVhd.Size / 1GB)
CommittedGB = ($GetVhd.FileSize / 1GB)
}
}

Related

Retrieving disk capacity with powershell

I made this code to count disk capacity, but when i run it with only the SSD in my laptop i get 0GB. after I insert USB/external space it count the ssd + the USB.
$disk = Get-WmiObject Win32_DiskDrive
$capacity = 0;
for($i = 0;$i -lt $disk.Count; $i++){
$capacity = $capacity + [math]::round(($disk[$i].Size/1GB),2)
}
Write-Host $capacity "GB"
This works fine -> $disk.Size
Why does it not take the first [0] in my for loop?
I cannot answer why your for loop is failing without observing your environment, but there is almost never a use-case for it. You should instead opt for a foreach loop:
$capacity = foreach ($disk in Get-WmiObject -Class Win32_DiskDrive)
{
[Math]::Round(($disk.Size / 1GB), 2)
}
"$(($capacity | Measure-Object -Sum).Sum)GB"
Assuming Windows 10 since you didn't mention OS and the CMDLETS in Windows 10 are so much better. *See at the bottom for a Windows 7 version.
For disk information, I prefer using Get-PhysicalDisk, like this for example:
$DiskInfo = foreach ($disk in Get-PhysicalDisk) {
[string]$name = $disk.FriendlyName
[string]$type = $disk.MediaType
[int]$capacity = $disk.size / 1GB
[pscustomobject]#{
"Type"=$type;
"Name"=$name;
"Capacity (GB)"=$capacity;
}
}
$DiskInfo
In my environement where I have one SSD and one mechanical HDD, it will return:
Name Type Capacity (GB)
---- ---- -------------
SAMSUNG MZ7TY256HDHP-000L7 SSD 238
ST500LX025-1U717D HDD 466
If you wanted information for JUST the SSD for example, you could do this :
$DiskInfo = foreach ($disk in Get-PhysicalDisk | Where-Object {$_.MediaType -eq "SSD"} ) {
[string]$name = $disk.FriendlyName
[string]$type = $disk.MediaType
[int]$capacity = $disk.size / 1GB
[pscustomobject]#{
"Type"=$type;
"Name"=$name;
"Capacity (GB)"=$capacity;
}
}
$DiskInfo
Which returns only the SSD:
Type Name Capacity (GB)
---- ---- -------------
SSD SAMSUNG MZ7TY256HDHP-000L7 238
Explanation: Foreach disk connected, store name, media type and capacity in variables. *Divide byte capacity by 1GB to get a better number to look at.
Still in the Foreach, create a custom object at every iteration containing the 3 variables.
All put together, you can then output your variable DiskInfo which contains all the objects.
If on Windows 7, media type isn't available so you can't use it. Instead you can do:
$DiskInfo = foreach ($disk in Get-WmiObject -Class Win32_DiskDrive) {
[string]$name = $disk.model
[int]$capacity = $disk.size / 1GB
[pscustomobject]#{
"Name"=$name;
"Capacity (GB)"=$capacity;
}
}
$DiskInfo
Which will return something like:
Name Capacity (GB)
---- -------------
SAMSUNG MZ7TY256HDHP-000L7 238
ST500LX025-1U717D 466

PowerShell Scripting for System Center VMM

Am new to scripting kindly help me write a script that will connect to VMM and get details such as below.
Name : ABC Machine
CPUCount : 8
Memory : 8192
DynamicMemoryEnabled : False
VHDType : DynamicallyExpanding
MaximumSize : 214748364800
Size : 4194304
Location : C:\ClusterStorage\Volume3\CRB\CRB Test Machine_disk_1.vhdx
Classification : Silver
VHDType : DynamicallyExpanding
MaximumSize : 4748364800
Size : 41304
Location : C:\ClusterStorage\Volume2\CRB\CRB Test Machine_disk_2.vhdx
Classification : Silver
I have been able to get individual commands to get the info however I am not able to make a script that will do it for all VMs and convert disk sizes to GB
My working commands are
Get-SCVirtualMachine -Name "ABC Machine" | select Name, CPUCount, Memory, DynamicMemoryEnabled | fl
$DiskINfo = Get-SCVirtualDiskDrive -VMMServer "abc.abcgroupcloud.com" -VM "ABC Machine"
$DiskINfo.VirtualHardDisk | select VHDType, MaximumSize, Size, Location, Classification
1- create an array with all the VM names (or read it from a file with get-content)
2- use a foreach loop to excecute you script over all these VM
3- use a calulated property to display the size in Gb
$computers=#("ABC machine","XYZ machine")
$computers | foreach-object {
Get-SCVirtualMachine -Name $_ | select Name, CPUCount, Memory, DynamicMemoryEnabled | fl
$DiskINfo = Get-SCVirtualDiskDrive -VMMServer "abc.abcgroupcloud.com" -VM $_
$DiskINfo.VirtualHardDisk | select VHDType, MaximumSize, #{Name="Size in Gb";Expression={$($_.size)Mb / 1Gb}}, Location, Classification
}
Old question, but just to add some info.
This will get all the Virtual Machines in your host group in VMM, after entering the correct host group name.
$VMs will be the array, which will contain all the details you are after.
$hg = Get-SCVMHostGroup -Name "My Hostgroup Name"
$hosts = Get-SCVMHost -VMHostGroup $hg
$VMs = $null
ForEach ($h in $hosts)
{
$VMs += Get-SCVirtualMachine -VMHost $h
}

Powershell - Create new line for multiple array objects using Export-csv

I have an odd one that I haven't seen much writing on. Anyway, here goes.
I'm trying to build an array and export it to CSV. The problem is, if there is more than one result returned, I can't figure out how to add it to the CSV as a new line. I am currently using a -join to throw all the results into the same cell, but that's not optimal. What I'd really like to do is add a new row and throw the extra results underneath it in the same column. Does that make sense? Here's what I have now:
# Grab all VMs, put into variable
$vms = Get-VM
# Use to build report
foreach ($vm in $vms){
New-Object PSObject -Property #{
VMName = $vm.Name
UsedSpaceGB = $vm.UsedSpaceGB
StorageAllocatedGB = ($vm.HardDisks.capacitygb | Measure-Object -Sum).Sum
NumberOfCPUs = $cm.NumCpu
MemoryGB = $vm.MemoryGB
Datastores = Get-Datastore -VM $vm
Application = ($vm | Get-Annotation -CustomAttribute Applications -ErrorAction SilentlyContinue).Value | select
} | select VMName,#{label="Application";expression={$_.Application -join ","}},UsedSpaceGB,StorageAllocatedGB,NumberOfCPUs,MemoryGB,#{l="Datastores";e={$_.Datastores -join ","}} | Export-Csv -Path C:\script\VMCapacityUsedByApp.csv -NoClobber -Append -NoTypeInformation
}
By the way, this is using VMware's PowerCLI snapin. Any help is greatly appreciated.
Ok, looks like datastores and applications are the only fields that are going to return arrays according to your previous code. Assuming that the $cm.NumCpu was supposed to be $vm.NumCpu the following code should do what you want. It will figure out if you have more datastores or applications, and then loop through expanding the arrays for those fields creating new records for the same VM listing additional datastores and applications until it runs out of records. I set it to only list all details of a VM on the first record, but I'm sure you can figure out how to alter that if needed. Try this code and see how it looks to you:
# Grab all VMs, put into variable
$vms = Get-VM
# Use to build report
foreach ($vm in $vms){
$TempVM = New-Object PSObject -Property #{
VMName = $vm.Name
UsedSpaceGB = $vm.UsedSpaceGB
StorageAllocatedGB = ($vm.HardDisks.capacitygb | Measure-Object -Sum).Sum
NumberOfCPUs = $cm.NumCpu
MemoryGB = $vm.MemoryGB
Datastores = Get-Datastore -VM $vm
Application = ($vm | Get-Annotation -CustomAttribute Applications -ErrorAction SilentlyContinue).Value
}
$Records = if($TempVM.Application.count -gt $TempVM.Datastores.Count){$TempVM.Application.Count}else{$TempVM.Datastores.Count}
$ExpandedVM = #()
$ExpandedVM += $TempVM|select Name,UsedSpaceGB,StorageAllocatedGB,NumberOfCPUs,MemoryGB,#{l="Datastores";e={$TempVM.Datastores[0]}},#{l="Application";e={$TempVM.Application[0]}}
for($i=1;$i -lt $Records;$i++){$ExpandedVM += $TempVM|select Name,#{l="Datastores";e={$TempVM.Datastores[$i]}},#{l="Application";e={$TempVM.Application[$i]}}}
$ExpandedVM | Export-Csv -Path C:\script\VMCapacityUsedByApp.csv -NoClobber -Append -NoTypeInformation
}
There may be a more elegant way to do it, but that should be functional for you at the very least. I don't have VM machines to test against, or the plugin you use, so I made up data that should be in line with what you're feeding it (strings for all fields except datastores and application both of which have their own array of strings) and ended up with output like this:
Name UsedSpaceGB StorageAllo NumberOfCP MemoryGB Datastores Applicatio
catedGB Us n
---- ----------- ----------- ---------- -------- ---------- ----------
TestVM 250 500 4 16 Store1 Word
TestVM Store2 Excel
TestVM Store3 Access
TestVM Outlook
TestVM2 487 500 4 32 StoreA WoW
TestVM2 StoreB SC2
TestVM2 StoreC D3
TestVM2 StoreD
TestVM2 StoreE
That is what you were looking for I think.

CPU core count from a Hyper-V host under SCVMM 2012

I asked this question on the TechNet forums without any luck (link), so I thought I'd see if anyone around here might have an answer:
At our company we have a VMM server (SCVMM 2012) controlling two physical Hyper-V hosts (let's call them HOST01 and HOST02). I'm trying to get some information about HOST01 via PowerShell queries on the VMM server:
Get-VMHost -ComputerName HOST01
..which among other things returns some CPU info:
...
LogicalProcessorCount = 12
PhysicalCPUCount = 1
CoresPerCPU = 12
L2CacheSize = 2048
L3CacheSize = 20480
BusSpeed = 100
ProcessorSpeed = 2294
ProcessorModel = Xeon
ProcessorManufacturer = Intel
ProcessorArchitecture = 9
ProcessorFamily = 179
CpuUtilization = 33
...
Now, I happen to know that HOST01 runs on a 6 core CPU with hyperthreading *), so LogicalProcessorCount = 12 is correct, but I expected to see CoresPerCPU = 6 (not 12). Why doesn't VMM show the correct number of physical cores? Am I looking in the wrong place?
Alternatively, is there a way to see whether hyperthreading is activated on the host, so I could divide by 2 as a last resort?
*) HOST01 is our own test server, so I have queried it separately through WMI to get CPU data, but in a production environment we cannot rely on having access to anything but the VMM server.
With Hyper-Threading enabled you get 2 logical processors per core. Since VMM cares only about the number of logical processors I doubt you'll be able to get "lower level" CPU information out of it. To get the actual number of cores for each CPU you have to query the processor information via WMI:
Get-WmiObject Win32_Processor -Computer HOST01 |
select Name, NumberOfCores, NumberOfLogicalProcessors
Edit: In a situation where user and host have no access at all to the hypervisors I don't think you'll be able to obtain that information. Not without making some changes to the infrastructure, that is. The following might provide a viable approach, if you have someone who can set it up on the VMM host for you.
Periodically collect the information from the hypervisors with a scheduled task running the following script on the VMM host:
$datafile = 'C:\path\to\data.csv'
$hypervisors = Get-SCVMHost | select -Expand Name
Get-WmiObject Win32_Processor -Computer $hypervisors |
select Name, NumberOfCores | Export-Csv $datafile -NoType -Encoding ASCII
Publish the content of the datafile with a custom web server on the VMM host:
$port = 8000
$datafile = 'C:\path\to\data.csv'
$lastUpdate = Get-Date 0
$data = ''
function Get-Data {
$filedate = (Get-Item $datafile).LastWriteTime
if ($filedate -gt $lastUpdate) {
$script:data = Import-Csv 'C:\Temp\text.csv' | ConvertTo-Json
$script:lastUpdate = $filedate
}
$script:data
}
If (-not (Test-Path -LiteralPath $datafile)) {
New-Item -ItemType File -Path $datafile | Out-Null
}
$listener = New-Object Net.HttpListener
$listener.Prefixes.Add("http://+:$port/")
$listener.Start()
while ($listener.IsListening) {
$response = $listener.GetContext().Response
$response.Headers.Add('Content-Type', 'text/plain')
$buffer = [Text.Encoding]::ASCII.GetBytes((Get-Data))
$response.ContentLength64 = $buffer.Length
$response.OutputStream.Write($buffer, 0, $buffer.Length)
$response.Close()
}
$listener.Stop()
If the Windows Firewall is enabled on the VMM host you need to open the listener port in it.
With that in place you can access the data from a server or workstation like this:
Invoke-WebRequest 'http://vmmserver:8000/' | select -Expand Content |
ConvertFrom-Json

Unable to retrieve physical size of available storage for cluster

I am half way down with my work and now stuck.
I am trying to fetch information about available storage devices for a cluster.
I am able to fetch the list of available storage devices but unable to retrieve the physical disk, available free space, etc of these available storage.
I want like this. Is there any command to fetch physical disk name from Cluster Disk Name or directly can I get the disk details.
For Shared Disk I am able to retrieve the details (Get-ClusterSharedVolume) but not for a non-shared disk.
I want powershell or WMI script for doing so.
You can get this information from WMI, but it takes a couple steps:
$resources = Get-WmiObject -namespace root\MSCluster MSCluster_Resource -filter "Type='Physical Disk'"
$resources | foreach {
$res = $_
$disks = $res.GetRelated("MSCluster_Disk")
$disks | foreach {
$_.GetRelated("MSCluster_DiskPartition") |
select #{N="Name"; E={$res.Name}}, #{N="Status"; E={$res.State}}, Path, VolumeLabel, TotalSize, FreeSpace
}
} | ft
That will give you output like the following:
Name Status Path VolumeLabel TotalSize FreeSpace
---- ------ ---- ----------- --------- ---------
Cluster Disk 2 2 K: New Volume 5220 5163
SQL - FAS3070 SiteB 2 S: MC_SQL 5597 5455
SM Test 2 M: SM Test 1024 992
DTC - FAS3070B 2 F: MC_WITNESS 5346 5289
Cluster Disk Witness 2 E: New Volume 5322 5267
Cluster Disk 1 2 G: MC_DTC 5088 5035
Cluster Disk 3 2 T: SQL 5119 4999
If you don't care about the resource name/status you can skip those steps and jump straight to the partition (and it'll run much quicker):
gwmi -namespace root\MSCluster MSCluster_DiskPartition | ft Path, VolumeLabel, TotalSize, FreeSpace
Edit: Note that the size is in MB and a Status of "2" means that the disk is online.
you can use wmi like this:
Get-WMIObject Win32_LogicalDisk -filter "DriveType=3" | Select DeviceID, FreeSpace
throw in a computername parameter if you wish to do it remotely
HTH,
Matt
PS. for a more readable report you can try this:
Get-WMIObject Win32_LogicalDisk -filter "DriveType=3" |
Select DeviceID, #{Name = "Free Space (%)" ; Expression= {[int] ($_.FreeSpace / $_.Size* 100)}},#{Name = "Free Space (GB)"; Expression = {[int]($_.Freespace / 1GB)}}, #{Name = "Size (GB)"; Expression = {[int]($_.Freespace / 1GB)}}