justinsmith
Enthusiast
Enthusiast

Misaligned VMDK's Powercli Script Help

Jump to solution

I have a script that I run against a vCenter server. Basically finds all vm's in vCenter and ruins a get-wmiobject command against them to get the VMNAME, Partition, Offset and Status and exports it to excel.

Here's a sample output of the data that gets exported to excel:

VMNamePartitionOffsetStatus
pdxvvmdb1Disk #0, Partition #18193150KBPartition NOT aligned
pdxvvmdb1Disk #0, Partition #18193150KBPartition NOT aligned

My "problem" is its not giving me the correct partition info in excel (via system info), see below.

It only has 1 vmdk with 2 partitions, so it should output both partition 1 and 2 and the offsets, since they're both incorrect?

Also looking to add a line to the script to add the datastore and the vmdk file location ([PDXESX1_RAID] pdxvvmdb1/pdxvvmdb1.vmdk) in this case and have that output to the excel. Possible?

I attached the script since its pretty long....

0 Kudos
1 Solution

Accepted Solutions
LucD
Leadership
Leadership

I made the same mistake you did in the beginning, the $Details object has to be created at the lowest level.

Like this

# Add-PSSnapin vmware.vimautomation.core
connect-viserver vspheredev
$myCol = @()
$mycol.Initialize()
$vms = get-vm | where {$_.PowerState -eq "PoweredOn" -and $_.Guest.OSFullName -match "Microsoft Windows*" } | Sort Name 
foreach($vm in $vms)
{           
    Try 
    {
        $wmi = get-wmiobject -class "Win32_DiskPartition" -namespace "root\CIMV2" -ComputerName $vm -ErrorAction silentlycontinue           
        foreach ($objItem in $wmi)
        {
            if ($objItem.StartingOffset % 64kb -eq 0){
                $Details = "" | Select-Object VMName, Partition, Offset, Status, VMDKPath
               
$Details.VMName = $vm.name
               
$details.VMDKPath = $vm.HardDisks[0].Filename
               
$Details.Partition = $objItem.Name
                $details.offset = "$([long]$($objitem.StartingOffset)/1KB)KB"
               
$Details.Status = "Partition aligned"                           }             else            {                 $Details = "" | Select-Object VMName, Partition, Offset, Status, VMDKPath
               
$Details.VMName = $vm.name
               
$details.VMDKPath = $vm.HardDisks[0].Filename
                $Details.Partition = $objItem.Name
                $details.offset = "$([long]$($objitem.StartingOffset)/1KB)KB"
               
$Details.Status = "Partition NOT aligned"                           }             $myCol += $Details        }    }    catch      {           $Details = "" | Select-Object VMName, Partition, Offset, Status, VMDKPath
        $Details.VMName = $vm.name
        $details.VMDKPath = ""
        $Details.Partition = "error"
        $details.offset = ""
        $Details.Status = "error"
        $myCol += $Details
    }          } $mycol  | Export-Csv -NoTypeInformation "H:\Excel_Reports\NEW_Production_PartitionAlignment.csv"
#output errors to file $error >>  "c:\temp\partition-check-errors.txt" $error.clear()

Note that in the VMDKPath property the script stores the path of the 1st VMDK.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

View solution in original post

0 Kudos
22 Replies
LucD
Leadership
Leadership

Since you creating the $Details object outside the partition loop, you are always referring to the same object.

In you $myCol there will be only 1 object for each VM.

Since you are using only 1 VMDK, you can find the datastorepath to the VMDK quite easy.

Something like this

# Add-PSSnapin vmware.vimautomation.core
connect-viserver vspheresea
$myCol = @()
$mycol.Initialize()
$vms = get-vm | where {$_.PowerState -eq "PoweredOn" -and ` $_.Guest.OSFullName -match "Microsoft Windows*" } | 
Sort Name foreach($vm in $vms) {     Try     {         $wmi = get-wmiobject -class "Win32_DiskPartition" -namespace "root\CIMV2" -ComputerName $vm -ErrorAction silentlycontinue                   foreach ($objItem in $wmi)         {             $Details = "" | Select-Object VMName, Partition, Offset, Status, VMDKPath
            $Details.VMName = $vm.name
            $details.VMDKPath = $vm.HardDisks[0].Filename
            if ($objItem.StartingOffset % 64kb -eq 0){                                 $Details.Partition = $objItem.Name
                $details.offset = "$([long]$($objitem.StartingOffset)/1KB)KB"
                $Details.Status = "Partition aligned"                           }             else
            {                
$Details.Partition = $objItem.Name
                $details.offset = "$([long]$($objitem.StartingOffset)/1KB)KB"
                $Details.Status = "Partition NOT aligned"                           }             $myCol += $Details
        }    }    catch   {         $Details = "" | Select-Object VMName, Partition, Offset, Status, VMDKPath
        $Details.VMName = $vm.name
        $Details.Partition = "error"
        $details.offset = ""
        $Details.Status = "error"
        $myCol += $Details
    }          }
$mycol  | Export-Csv -NoTypeInformation "H:\Excel_Reports\Production_PartitionAlignment.csv" #output errors to file $error >>  "c:\temp\partition-check-errors.txt"
$error.clear()


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
justinsmith
Enthusiast
Enthusiast

Brilliant.... what about the VM's that actually have multiple VMDK's though? Will it list out all, if any?

0 Kudos
LucD
Leadership
Leadership

Ah, now that is a problem. There is, afaik, no fool-proof way to make a link between the VMDK and the partitions you create in the guest OS.

That's why I said that with 1 VMDK it is possible, but with more than 1 VMDK, it's a problem I'm afraid.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
justinsmith
Enthusiast
Enthusiast

Good to know.

It still doesnt look like the script is getting the right data though. For instance, output data:

VMNamePartitionOffsetStatus
seavvafile2Disk #1, Partition #032KBPartition NOT aligned
seavvafile2Disk #1, Partition #032KBPartition NOT aligned

System Info data:

"Didnt paste in, see attached file."

This VM has 2 VMDK's (which I dont really care about) but Im assuming if it out put the right info in the spreadsheet (Disk #0, partition #0, and disk #1 partition #0) I could put 2 and 2 together and assume that there are 2 VMDK's since there are 2 Disks showing in the Partition column.

0 Kudos
LucD
Leadership
Leadership

Didn't you get the VMDKPath property ?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
LucD
Leadership
Leadership

I just tested on a VM with 4 VMDK and 2 partitions on the first disk.

Looked ok to me

align.png


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
justinsmith
Enthusiast
Enthusiast

I had to play around with the script you pasted... running it now to see what it comes up with.

0 Kudos
justinsmith
Enthusiast
Enthusiast

Is yours outputting the proper VMDK path?

jsmith1Disk #1, Partition #031.5KBPartition NOT aligned[DS1] jsmith1/jsmith1.vmdk
jsmith1Disk #1, Partition #031.5KBPartition NOT aligned[DS1] jsmith1/jsmith1.vmdk

Mine is still showing the duplicate disk # and the VMDK location is the same.

The bottom VMDK should be [DS] jsmith1/jsmith1_1.vmdk and the tiop disk should be Disk #0 Partition #0.... while the bottom should be Disk #1, Partition #0

I attached the script to see if Im missing anything

0 Kudos
LucD
Leadership
Leadership

I made the same mistake you did in the beginning, the $Details object has to be created at the lowest level.

Like this

# Add-PSSnapin vmware.vimautomation.core
connect-viserver vspheredev
$myCol = @()
$mycol.Initialize()
$vms = get-vm | where {$_.PowerState -eq "PoweredOn" -and $_.Guest.OSFullName -match "Microsoft Windows*" } | Sort Name 
foreach($vm in $vms)
{           
    Try 
    {
        $wmi = get-wmiobject -class "Win32_DiskPartition" -namespace "root\CIMV2" -ComputerName $vm -ErrorAction silentlycontinue           
        foreach ($objItem in $wmi)
        {
            if ($objItem.StartingOffset % 64kb -eq 0){
                $Details = "" | Select-Object VMName, Partition, Offset, Status, VMDKPath
               
$Details.VMName = $vm.name
               
$details.VMDKPath = $vm.HardDisks[0].Filename
               
$Details.Partition = $objItem.Name
                $details.offset = "$([long]$($objitem.StartingOffset)/1KB)KB"
               
$Details.Status = "Partition aligned"                           }             else            {                 $Details = "" | Select-Object VMName, Partition, Offset, Status, VMDKPath
               
$Details.VMName = $vm.name
               
$details.VMDKPath = $vm.HardDisks[0].Filename
                $Details.Partition = $objItem.Name
                $details.offset = "$([long]$($objitem.StartingOffset)/1KB)KB"
               
$Details.Status = "Partition NOT aligned"                           }             $myCol += $Details        }    }    catch      {           $Details = "" | Select-Object VMName, Partition, Offset, Status, VMDKPath
        $Details.VMName = $vm.name
        $details.VMDKPath = ""
        $Details.Partition = "error"
        $details.offset = ""
        $Details.Status = "error"
        $myCol += $Details
    }          } $mycol  | Export-Csv -NoTypeInformation "H:\Excel_Reports\NEW_Production_PartitionAlignment.csv"
#output errors to file $error >>  "c:\temp\partition-check-errors.txt" $error.clear()

Note that in the VMDKPath property the script stores the path of the 1st VMDK.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
justinsmith
Enthusiast
Enthusiast

I get a parsing error on line 5. Right after the -and. It looks like it needs a value?

$vms = get-vm | where {$_.PowerState -eq "PoweredOn" -and ` $_.Guest.OSFullName -match "Microsoft Windows*" } | Sort Name

0 Kudos
LucD
Leadership
Leadership

That back-tick had to go, I updated the code above


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
justinsmith
Enthusiast
Enthusiast

Its parsing out the info into excel properly now, but like you said, is only going to populate the one VMDK file path...

Im not sure I need this info, but it wont hurt to be in the script.

Thanks!

0 Kudos
justinsmith
Enthusiast
Enthusiast

Im looking to add Disk and Partition into separate tabs at the top, so I can filter them based on one or the other.

Is there a way to separate the 2?

From the looks of it, theres only a Partition Item in System Information.....

0 Kudos
LucD
Leadership
Leadership

The Split function would do that. Something like this

$Details.Disk,$Details.Partition = $objItem.Name.Split(',')

You will need to add the property Disk to the $Details object.

The $ObjItem.Name is split at the comma, the first part goes to $Details.Disk, the 2nd part goes to $Details.Partition.

Let me know if that works for you.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
justinsmith
Enthusiast
Enthusiast

Im not that familiar with the split command, but I did add

$Details = "" | Select-Object VMName, Disk, Partition, Offset, Status, VMDKPath

to the 3 different areas of the script.

Do I need to add the line below to all the 3 $Details fields below that too? Or just one?

$Details.Disk,$Details.Partition = $objItem.Name.Split(',')

I've added all 3 to the "if, else, and catch" details section but Im thinking thats wrong....

EDIT:

I've done a find/replace in excel to get rid of ", Partition #0", ", Partition #1" etc... Seems to get rid of the data I dont need.

I'll keep playing with the script though.

0 Kudos
LucD
Leadership
Leadership

I meant like this

# Add-PSSnapin vmware.vimautomation.core
connect-viserver vspheredev $myCol = @()
$mycol.Initialize()
$vms = get-vm | where {$_.PowerState -eq "PoweredOn" -and $_.Guest.OSFullName -match "Microsoft Windows*" } | Sort Name 
foreach($vm in $vms)
{           
    Try 
    {
        $wmi = get-wmiobject -class "Win32_DiskPartition" -namespace "root\CIMV2" -ComputerName $vm -ErrorAction silentlycontinue           
        foreach ($objItem in $wmi)
        {
            if ($objItem.StartingOffset % 64kb -eq 0){
                $Details = "" | Select-Object VMName, Disk, Partition, Offset, Status, VMDKPath
                $Details.VMName = $vm.name                $details.VMDKPath = $vm.HardDisks[0].Filename
                $Details.Disk,$Details.Partition = $objItem.Name.Split(',')                 $details.offset = "$([long]$($objitem.StartingOffset)/1KB)KB"
               
$Details.Status = "Partition aligned"                           }             else            {                 $Details = "" | Select-Object VMName, Disk, Partition, Offset, Status, VMDKPath
               
$Details.VMName = $vm.name
                $details.VMDKPath = $vm.HardDisks[0].Filename
               
$Details.Disk,$Details.Partition = $objItem.Name.Split(',')                 $details.offset = "$([long]$($objitem.StartingOffset)/1KB)KB"
               
$Details.Status = "Partition NOT aligned"                           }             $myCol += $Details        }    }    catch      {           $Details = "" | Select-Object VMName, Disk, Partition, Offset, Status, VMDKPath
       
$Details.VMName = $vm.name
       
$details.VMDKPath = ""
       
$Details.Disk = "error"
       
$Details.Partition = "error"
       
$details.offset = ""
       
$Details.Status = "error"
        $myCol += $Details
    }          } $mycol  | Export-Csv -NoTypeInformation "H:\Excel_Reports\NEW_Production_PartitionAlignment.csv"
#output errors to file $error >>  "c:\temp\partition-check-errors.txt" $error.clear()


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
justinsmith
Enthusiast
Enthusiast

I had to move some lines around but that did the trick.

As always... thanks again!

0 Kudos
justinsmith
Enthusiast
Enthusiast

Would there be an easy way to add the wmiobject to get the OS?

The -class is different (its Win32_OperatingSystem) and the option would be .Caption.

Would I need to call the get-wmiobject all over again? I've tried to add a couple different options (See below) but I dont think Powershell lets you add one class?

$wmi = get-wmiobject -class "Win32_DiskPartition" , "Win32_OperatingSystem" -namespace "root\CIMV2" -ComputerName $vm -ErrorAction silentlycontinue          
foreach ($objItem in $wmi)

0 Kudos
LucD
Leadership
Leadership

Afaik the Class parameter on the Get-WMiObject cmdlet only accepts a [string], not an array [string[]].

So you would have to do 2 calls


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos