I would like to match the drive in the windows os to the vCenter *.vmdk.
Here is a link for the informations I need. I find no way to get "Location 192 (Bus Number 0, Target Id 0, LUN 0)" with powershell (info from disk). From the WMI I don't get this information...
Can someone help?
The modified script:
$Vm = "VMName"
if (($VmView = Get-View -ViewType VirtualMachine -Filter #{"Name" = $Vm})) {
$Out = Get-WmiObject -Class win32_diskdrive -Property Index, SCSIPort, SCSITargetId -ComputerName $Vm
#Invoke-VMScript "wmic path win32_diskdrive get Index, SCSIPort, SCSITargetId /format:csv" -vm $VM -scripttype "bat"
foreach ($VirtualSCSIController in ($VMView.Config.Hardware.Device | where {$_.DeviceInfo.Label -match "SCSI-Controller"})) {
foreach ($VirtualDiskDevice in ($VMView.Config.Hardware.Device | where {$_.ControllerKey -eq $VirtualSCSIController.Key})) {
$VirtualDisk = "" | Select SCSIController, DiskName, SCSI_Id, DiskFile, DiskSize, WindowsDisk
$VirtualDisk.SCSIController = $VirtualSCSIController.DeviceInfo.Label
$VirtualDisk.DiskName = $VirtualDiskDevice.DeviceInfo.Label
$VirtualDisk.SCSI_Id = "$($VirtualSCSIController.BusNumber) : $($VirtualDiskDevice.UnitNumber)"
$VirtualDisk.DiskFile = $VirtualDiskDevice.Backing.FileName
$VirtualDisk.DiskSize = $VirtualDiskDevice.CapacityInKB * 1KB / 1GB
# Match disks based on SCSI ID
$DiskMatch = $Out | ?{($_.SCSIPort - 2) -eq $VirtualSCSIController.BusNumber -and $_.SCSITargetID -eq $VirtualDiskDevice.UnitNumber}
if ($DiskMatch){
$VirtualDisk.WindowsDisk = "Disk $($DiskMatch.Index)"
}
else {Write-Host "No matching Windows disk found for SCSI id $($VirtualDisk.SCSI_Id)"}
$DiskInfo += $VirtualDisk
}
}
$DiskInfo | Out-GridView
I had to change $DiskMatch = $Out | ?{($_.SCSIPort - 2) -eq <-- Replace - 1 with - 2.
And put an "-" between SCSI Controller by {$_.DeviceInfo.Label -match "SCSI-Controller"})).
Why do I have to subtract 2 from the SCSIPort?
The following script will match the local windows disk with the vmWare disk.
Date : 2017.10.27 21:28:01
vCenterName : vCenterName
vmName : SERVER
vmWareSCSIController : SCSI controller 0
wmWareSCSIID : 0 : 0
vmWareDiskName : Hard disk 1
vmWareDiskFile : [Datastore] vm.vmdk
vmWareSizeGB : 40
WindowsSerialNumber : WindowsSerialNumber
WindowsSCSIBus : 0
WindowsSCSILogicalUnit : 0
WindowsSCSIPort : 2
WindowsSCSITargetId : 0
WindowsDisk : \\SERVER\root\cimv2:Win32_DiskDrive.DeviceID="\\\\.\\PHYSICALDRIVE0"
WindowsDriveLetter : C:
WindowsLocicalDiskSizeGB : 39.9980430603027
WindowsLocicalDiskFreeSpaceGB : 9.30975723266602
WindowsLocicalDiskUsedSpaceGB : 30.6882858276367
#Variables
$Vm = Get-VM -Name 'VMName'
$ComputerName = 'ComputerName'
$obj_DiskDrive = #()
$obj_LogicalDisk = #()
$obj_LogicalDiskToPartition = #()
$obj_DiskDriveToDiskPartition = #()
$obj_VMView = #()
$obj_DiskInfos = #()
#Get wmi objects
$obj_DiskDrive = Get-WmiObject -Class win32_DiskDrive -ComputerName $ComputerName
$obj_LogicalDisk = Get-WmiObject -Class Win32_LogicalDisk -ComputerName $ComputerName
$obj_LogicalDiskToPartition = Get-WmiObject -Class Win32_LogicalDiskToPartition -ComputerName $ComputerName
$obj_DiskDriveToDiskPartition = Get-WmiObject -Class Win32_DiskDriveToDiskPartition -ComputerName $ComputerName
#Get vm
$obj_VMView = Get-View -ViewType VirtualMachine -Filter #{"Name" = "$($Vm.Name)"}
#Get vm disk
$obj_VMDisk = Get-HardDisk -VM $Vm
#Match the informations
foreach ($obj_vmWareSCSIController in ($obj_VMView.Config.Hardware.Device | Where-Object -FilterScript {$_.DeviceInfo.Label -match "SCSI"}))
{
foreach ($obj_vmWareDiskDevice in ($obj_VMView.Config.Hardware.Device | Where-Object -FilterScript {$_.ControllerKey -eq $obj_vmWareSCSIController.Key}))
{
$obj_tempDiskInfos = "" | Select-Object -Property Date, vCenterName, vmName, vmWareSCSIController, wmWareSCSIID, vmWareDiskName, vmWareDiskFile,
vmWareSizeGB, WindowsSerialNumber, WindowsSCSIBus, WindowsSCSILogicalUnit, WindowsSCSIPort, WindowsSCSITargetId, WindowsDisk, WindowsDriveLetter,
WindowsLocicalDiskSizeGB, WindowsLocicalDiskFreeSpaceGB, WindowsLocicalDiskUsedSpaceGB
#Select WMI object
$obj_currentDiskDrive = #()
$obj_currentDiskDrive = $obj_DiskDrive | Where-Object -FilterScript {$_.SerialNumber -eq $obj_vmWareDiskDevice.Backing.Uuid.Replace("-","")}
$obj_currentDiskDriveToDiskPartition = #()
$obj_currentDiskDriveToDiskPartition = $obj_DiskDriveToDiskPartition | Where-Object -FilterScript {$_.Antecedent -eq $obj_currentDiskDrive.Path}
$obj_currentLogicalDiskToPartition = #()
$obj_currentLogicalDiskToPartition = $obj_LogicalDiskToPartition | Where-Object -FilterScript {$_.Antecedent -eq $obj_currentDiskDriveToDiskPartition.Dependent}
$obj_currentLogicalDisk = #()
$obj_currentLogicalDisk = $obj_LogicalDisk | Where-Object -FilterScript {$_.Path.Path -eq $obj_currentLogicalDiskToPartition.Dependent}
#Select vmWare object
$obj_CurrentvmWareHarddisk = #()
$obj_CurrentvmWareHarddisk = $obj_VMDisk | Where-Object -FilterScript {$_.Name -eq $obj_vmWareDiskDevice.DeviceInfo.Label}
#Generate output
$obj_tempDiskInfos.Date = Get-Date -Format "yyyy.MM.dd HH:mm:ss"
$obj_tempDiskInfos.vCenterName = $defaultVIServer.Name
$obj_tempDiskInfos.vmName = $Vm.Name
$obj_tempDiskInfos.vmWareSCSIController = $obj_vmWareSCSIController.DeviceInfo.Label
$obj_tempDiskInfos.wmWareSCSIID = "$($obj_vmWareSCSIController.BusNumber) : $($obj_vmWareDiskDevice.UnitNumber)"
$obj_tempDiskInfos.vmWareDiskName = $obj_vmWareDiskDevice.DeviceInfo.Label
$obj_tempDiskInfos.vmWareDiskFile = $obj_vmWareDiskDevice.Backing.FileName
$obj_tempDiskInfos.vmWareSizeGB = $obj_CurrentvmWareHarddisk.CapacityGB
$obj_tempDiskInfos.WindowsSerialNumber = $obj_currentDiskDrive.SerialNumber
$obj_tempDiskInfos.WindowsSCSIBus = $obj_currentDiskDrive.SCSIBus
$obj_tempDiskInfos.WindowsSCSILogicalUnit = $obj_currentDiskDrive.SCSILogicalUnit
$obj_tempDiskInfos.WindowsSCSIPort = $obj_currentDiskDrive.SCSIPort
$obj_tempDiskInfos.WindowsSCSITargetId = $obj_currentDiskDrive.SCSITargetId
$obj_tempDiskInfos.WindowsDisk = $obj_currentDiskDrive.Path.Path
$obj_tempDiskInfos.WindowsDriveLetter = ($obj_currentLogicalDisk).Caption
$obj_tempDiskInfos.WindowsLocicalDiskSizeGB = $obj_currentLogicalDisk.Size / 1GB
$obj_tempDiskInfos.WindowsLocicalDiskFreeSpaceGB = $obj_currentLogicalDisk.FreeSpace / 1GB
$obj_tempDiskInfos.WindowsLocicalDiskUsedSpaceGB = ($obj_currentLogicalDisk.Size / 1GB) - ($obj_currentLogicalDisk.FreeSpace / 1GB)
$obj_DiskInfos += $obj_tempDiskInfos
}
}
$obj_DiskInfos
Related
Below Function is not running the lines "If ($script:AADServersTable)" down... I have put a write-host and that is working, however the variables are not working below that
Function get-AADVariables
{
$script:AADServersTable = New-Object 'System.Collections.Generic.List[System.Object]'
$scriptBlockaadinstalled = {
Get-WmiObject -Class Win32_Product |
where name -eq "Microsoft Azure AD Connect synchronization services" | select Name, Version}
##$scriptBlockaadinstalled = {hostname}
Import-Module ActiveDirectory
$servers = Get-ADComputer -Filter 'operatingsystem -like "*server*" -and enabled -eq "true"' | Select-Object -Property Name -ExcludeProperty Release
## just a single invoke-command
foreach ($server in $servers) {
$aadinstalledresults = Invoke-Command -ComputerName $server.name -ScriptBlock $scriptBlockaadinstalled ##-HideComputerName
$aadinstalledresults = $aadinstalledresults.PSComputerName
$script:AADServersTable.Add($aadinstalledresults)
}
If ($script:AADServersTable) {
Write-Host 'working'
$AADServers = ($script:AADServersTable | Group-Object -NoElement).Name | Get-Unique
$AADServers = $AADServers -split "`n"
$AADServer = $AADServers[0]
$StandByAADServer = $AADServers[1]
$SecondStandByAADServer = $AADServers[2]
}
}
I built this, which is working fine, it takes about 7-9 seconds to run and display.
I'm wondering, is there a faster/optimal way of building this custom object?
As you can see, I want all the drivers information from Win32_PNPsigneddriver but to that, I add two other properties from Win32_PNPentity (configmanagererrorcode and status) based on the DeviceID.
This way, the final object contains all drivers and shows if there is an error for the device using that driver.
$poste = "COMPUTER1234"
$DriversUp = Get-WmiObject -computername $poste Win32_PNPsigneddriver |
Where-Object {$_.DeviceName -ne $null}
$Devices = Get-WmiObject -computername $poste Win32_PNPentity
$DriversDevices = foreach ($driver in $DriversUp) {
$driver |
Select-Object DeviceClass, Manufacturer, DeviceName,
FriendlyName, DriverName, InfName,
#{name='Status';expression={$Devices | Where-Object {$_.DeviceID -eq "$($driver.DeviceID)"} | Select-Object -ExpandProperty status}},
#{name='ConfigManagerErrorCode';expression={$Devices | Where-Object {$_.DeviceID -eq "$($driver.DeviceID)"} | Select-Object -ExpandProperty ConfigManagerErrorCode}},
#{name='DriverDate';expression={[DateTime]::ParseExact(($_.DriverDate).Split('.')[0], "yyyyMMddHHmmss", [System.Globalization.CultureInfo]::InvariantCulture)}},
DriverVersion
}
$DriversDevices |
Sort-Object DeviceClass |
Out-GridView -Title "$poste - Drivers utilisés"
Like I said everything works fine already. However, I'm curious to know if there's a faster way!
Starting in PowerShell 3.0, the Get-WmiObject cmdlet has been superseded by Get-CimInstance.
$poste = "COMPUTER1234"
$cimses = New-CimSession -ComputerName $poste
$p = & {$args} DeviceClass Manufacturer DeviceName FriendlyName DriverName `
InfName DriverVersion DeviceID DriverDate
Get-CimInstance -CimSession $cimses -ClassName Win32_PnPSignedDriver `
-Property $p -Filter 'DeviceName != NULL' |
ForEach-Object {
$dev = Get-CimInstance -CimSession $cimses -ClassName Win32_PnPEntity `
-Property Status, ConfigManagerErrorCode `
-Filter "PNPDeviceID='$($_.DeviceID.Replace('\', '\\'))'"
[pscustomobject]#{
DeviceClass = $_.DeviceClass
Manufacturer = $_.Manufacturer
DeviceName = $_.DeviceName
FriendlyName = $_.FriendlyName
DriverName = $_.DriverName
InfName = $_.InfName
Status = $dev.Status
ConfigManagerErrorCode = $dev.ConfigManagerErrorCode
DriverDate = '{0:yyyyMMddHHmmss}' -f $_.DriverDate
DriverVersion = $_.DriverVersion
}
} | Sort-Object DeviceClass | Out-GridView -Title "$poste - Drivers utilisés"
Remove-CimSession -CimSession $cimses
On my machine, the type of the Win32_PnPSignedDriver.DriverDate member is DateTime.
Get-CimClass -ClassName Win32_PnPSignedDriver |
Select-Object -ExpandProperty CimClassProperties |
Where-Object Name -eq 'DriverDate' |
Select-Object CimType | Format-Table -AutoSize
CimType
-------
DateTime
The bottleneck is searching for a device every time using Where-Object.
The following code uses Group-Object to solve the issue.
$poste = "COMPUTER1234"
$DriversUp = Get-WmiObject -ComputerName $poste Win32_PnPSignedDriver -Filter "DeviceName != NULL"
$Devices = Get-WmiObject -ComputerName $poste Win32_PnPEntity -Property DeviceID,Status,ConfigManagerErrorCode
#($DriversUp; $Devices) | Group-Object DeviceID | Where-Object Count -eq 2 | ForEach-Object {
$driver, $device = $_.Group
[pscustomobject]#{
DeviceClass = $driver.DeviceClass
Manufacturer = $driver.Manufacturer
DeviceName = $driver.DeviceName
FriendlyName = $driver.FriendlyName
DriverName = $driver.DriverName
InfName = $driver.InfName
Status = $device.Status
ConfigManagerErrorCode = $device.ConfigManagerErrorCode
DriverDate = [datetime]::ParseExact($driver.DriverDate.Substring(0, 14), "yyyyMMddHHmmss", $null)
DriverVersion = $driver.DriverVersion
}
} | Sort-Object DeviceClass | Out-GridView -Title "$poste - Drivers utilisés"
This is how I would do it, not big difference in performance, but more clear IMO:
Used an ArrayList for the results, also replaced the Where-Object on the Get-WmiObject with -Filter, it's a bit faster...
$poste = "COMPUTER1234"
$DriversUp = Get-WmiObject -computername $poste Win32_PNPsigneddriver -Filter "DeviceName != NULL"
$Devices = Get-WmiObject -computername $poste Win32_PNPentity
$DriversDevices = New-Object System.Collections.ArrayList
foreach ($driver in $DriversUp) {
$row = "" | Select DeviceClass,Manufacturer,DeviceName,FriendlyName,DriverName,
InfName,Status,ConfigManagerErrorCode,DriverDate,DriverVersion
$row.DeviceClass = $driver.DeviceClass
$row.Manufacturer = $driver.Manufacturer
$row.DeviceName = $driver.DeviceName
$row.DriverName = $driver.DriverName
$row.InfName = $driver.InfName
$row.Status = ($Devices | ? {$_.DeviceID -eq $driver.DeviceID}).Status
$row.ConfigManagerErrorCode = ($Devices | ? {$_.DeviceID -eq $driver.DeviceID}).ConfigManagerErrorCode
$row.DriverDate = [datetime]::ParseExact(($driver.DriverDate.Split('.')[0]),"yyyyMMddHHmmss",$null)
$row.DriverVersion = $driver.DriverVersion
[void]$DriversDevices.Add($row)
}
$DriversDevices | Sort-Object DeviceClass | Out-GridView -Title "$poste - Drivers utilisés"
I am very close to what I am looking for, I have all of the correct data and it is just not formatting correctly. Currently it is all in one column, and what I would like is for the headers to be in a row, and then each entry to be in its own row as well. Here is my current code:
$servers = Get-ADComputer -Filter "Name -like 'f****p*'" | Sort-Object | Select -ExpandProperty Name
$servers | foreach {
$server = $_
$serverIP = Test-Connection -ComputerName $server -Count 1 | Select -ExpandProperty IPV4Address
$serverIPString = $serverIP.IPAddresstoString
$scope = Get-DhcpServerv4Scope -ComputerName $server
$options = Get-DhcpServerv4OptionValue -ComputerName $server
New-Object -TypeName psobject -Property #{
ServerName = $server
ServerIP = $serverIPString
ScopeName = $scope.Name | Out-String
StartIP = $scope.StartRange.IPAddressToString | Out-String
EndIP = $scope.EndRange.IPAddressToString | Out-String
SubnetMask = $scope.SubnetMask.IPAddressToString | Out-String
Duration = $scope.LeaseDuration.Days | Out-String
OptionName = $options.Name | Out-String
OptionID = $options.OptionID | Out-String
OptionValue = $options.Value | Out-String
}
} | Select-Object ServerName, ServerIP, ScopeName, StartIP, EndIP, SubnetMask, Duration, OptionName, OptionID, OptionValue | Out-File C:\temp\FPScopes.csv
Currently the output looks like this example (using Duration and Options as an example, as it has the most generic data to share):
What I am looking for would be to have each object type as a column header, and have the entries in a separate row underneath the header:
Etc....
Any assistance would be greatly appreciated.
Thank you! :)
Ry
My final code, after help from this forum:
Add-Content -Value "ServerName,ServerIP,ScopeName,StartRange,EndRange,SubnetMask,Duration,OptionName,OptionID,Value" -Path c:\temp\POSScopes.csv
Get-ADComputer -Filter {Name -like 'p****p01' -or Name -like 'p****p02' -or Name -like 'q****001' -or Name -like 'q****002'} | Sort-Object | Select -ExpandProperty Name | Out-File C:\Temp\POSServers.txt
$servers = Get-Content C:\Temp\POSServers.txt
$servers | foreach {
$server = $_
$serverIP = Test-Connection -ComputerName $server -Count 1 | Select -ExpandProperty IPV4Address
$serverIPString = $serverIP.IPAddresstoString
$scope = Get-DhcpServerv4Scope -ComputerName $server
$options = Get-DhcpServerv4OptionValue -ComputerName $server
New-Object -TypeName psobject -Property #{
ServerName = $server
ServerIP = $serverIPString
ScopeName = $scope.Name | Out-String
StartIP = $scope.StartRange.IPAddressToString | Out-String
EndIP = $scope.EndRange.IPAddressToString | Out-String
SubnetMask = $scope.SubnetMask.IPAddressToString | Out-String
Duration = $scope.LeaseDuration.Days | Out-String
OptionName = $options.Name | Out-String
OptionID = $options.OptionID | Out-String
OptionValue = $options.Value | Out-String
}
for ($i = ($Options.Count -1); $i -gt -1; $i--) {
Add-Content -Value "$($server),$($serverIPString),$($scope.Name),$($scope.StartRange.IPAddressToString),$($scope.EndRange.IPAddressToString),$($scope.SubnetMask.IPAddressToString),$($scope.LeaseDuration.Days),$($options[$i].Name),$($options[$i].OptionID),$($Options[$i].Value)" -Path C:\temp\POSScopes.csv
}
}
Add-Content -Value "ServerName,ServerIP,ScopeName,StartRange,EndRange,SubnetMask,Duration,OptionName,OptionID,Value" -Path c:\temp\POSScopes.csv
Get-ADComputer -Filter {Name -like 'p****p01' -or Name -like 'p****p02' -or Name -like 'q****001' -or Name -like 'q****002'} | Sort-Object | Select -ExpandProperty Name | Out-File C:\Temp\POSServers.txt
$servers = Get-Content C:\Temp\POSServers.txt
$servers | foreach {
$server = $_
$serverIP = Test-Connection -ComputerName $server -Count 1 | Select -ExpandProperty IPV4Address
$serverIPString = $serverIP.IPAddresstoString
$scope = Get-DhcpServerv4Scope -ComputerName $server
$options = Get-DhcpServerv4OptionValue -ComputerName $server
New-Object -TypeName psobject -Property #{
ServerName = $server
ServerIP = $serverIPString
ScopeName = $scope.Name | Out-String
StartIP = $scope.StartRange.IPAddressToString | Out-String
EndIP = $scope.EndRange.IPAddressToString | Out-String
SubnetMask = $scope.SubnetMask.IPAddressToString | Out-String
Duration = $scope.LeaseDuration.Days | Out-String
OptionName = $options.Name | Out-String
OptionID = $options.OptionID | Out-String
OptionValue = $options.Value | Out-String
}
for ($i = ($Options.Count -1); $i -gt -1; $i--) {
Add-Content -Value "$($server),$($serverIPString),$($scope.Name),$($scope.StartRange.IPAddressToString),$($scope.EndRange.IPAddressToString),$($scope.SubnetMask.IPAddressToString),$($scope.LeaseDuration.Days),$($options[$i].Name),$($options[$i].OptionID),$($Options[$i].Value)" -Path C:\temp\POSScopes.csv
}
}
How to get the jobs output in an CSV format. When I execute the command below, I get the output on the screen, but when I export it to CSV it does not have the same format.
$wmidiskblock = {
Get-WmiObject -ComputerName $args[0] -Class Win32_LogicalDisk -Filter "DeviceID='C:'" |
Select-Object Size, Freespace
(Test-Connection -ComputerName $args[0] | Select-Object -ExpandProperty IPV4Address) |
Select-Object IPAddressToString -Unique
Get-Service -ComputerName $args[0] | ? {
($_.DisplayName -match "VMWARE") -and
($_.Name -notmatch "mbcs") -and
($_.Name -notmatch "vmvss") -and
($_.Name -notmatch "vmware-autodeploy-waiter") -and
($_.Name -notmatch "vmware-network-coredump") -and
($_.Name -notmatch "VMWareNetworkCoredumpWebserve") -and
($_.Name -notmatch "vsan-health")
} -ErrorAction Stop
}
$com = #()
$com = "Server-x" , "Server-y"
$pop = #()
foreach ($ser in $com) {
[array]$pop += Start-Job -ArgumentList $ser -ScriptBlock $wmidiskblock -Name top1
}
Get-Job -Name top1 | Receive-Job -Keep
Actual output:
Size : 64422408192
Freespace : 4908081152
RunspaceId : cdb3xxxxx-xxxx-xxxx-xxxx-xxxxxxxxx
IPAddressToString : x.x.x.x
RunspaceId : cdb3xxxxx-xxxx-xxxx-xxxx-xxxxxxxxx
Status : Running
Name : client_service
DisplayName : VMware Horizon Client
Status : Running
Name : ftnlsv3hv
DisplayName : VMware Netlink Supervisor Service
Status : Running
Name : ftscanmgrhv
DisplayName : VMware Scanner Redirection Client
Server-x
Desired output (as a CSV file):
Server Totalspace in GB Freespace in GB IP VMware ESX Agent Manager VMware Inventory Service
Server-x 100 36 144.215.150.67 Running Running
You need to transform your data to something that's actually exportable to CSV. Basically that means you need to take the bits of information you extract from the servers and put it into one object for each server:
$wmidiskblock = {
$disk = Get-WmiObject ...
$addr = (Test-Connection ...
$svc = Get-Service ...
$prop = [ordered]#{
Server = $args[0]
Totalspace = $disk.Size
Freespace = $disk.Freespace
IP = $addr
}
$svc | ForEach-Object { $prop[$_.Name] = $_.Status }
New-Object -Type PSObject -Property $prop
}
Then you can export the data received from the jobs like this:
... | Receive-Job | Export-Csv 'C:\path\to\output.csv' -NoType -Append
I'm trying to utilize WMI via PowerShell to run through SAN storage on remote servers to grab the Windows disk management volume label.
The only way I've found to do this is to correlate the volume device id (\\?\Volume{34243...} with the physical disk device ID (\\.\PHYSICALDRIVE01).
However, I haven't been able to find out how to link those two fields together. Is this possible with WMI?
For volumes that were assigned a drive letter you can correlate disks and volumes like this:
Get-WmiObject Win32_DiskDrive | ForEach-Object {
$disk = $_
$partitions = "ASSOCIATORS OF " +
"{Win32_DiskDrive.DeviceID='$($disk.DeviceID)'} " +
"WHERE AssocClass = Win32_DiskDriveToDiskPartition"
Get-WmiObject -Query $partitions | ForEach-Object {
$partition = $_
$drives = "ASSOCIATORS OF " +
"{Win32_DiskPartition.DeviceID='$($partition.DeviceID)'} " +
"WHERE AssocClass = Win32_LogicalDiskToPartition"
Get-WmiObject -Query $drives | ForEach-Object {
$driveLetter = $_.DeviceID
$fltr = "DriveLetter='$driveLetter'"
New-Object -Type PSCustomObject -Property #{
Disk = $disk.DeviceID
DriveLetter = $driveLetter
VolumeName = $_.VolumeName
VolumeID = Get-WmiObject -Class Win32_Volume -Filter $fltr |
Select-Object -Expand DeviceID
}
}
}
}
Otherwise it doesn't seem possible with WMI.
On Windows 8/Server 2012 or newer you could use the Get-Partition cmdlet, though:
Get-Partition | Select-Object DiskNumber, DriveLetter, #{n='VolumeID';e={
$_.AccessPaths | Where-Object { $_ -like '\\?\volume*' }
}}
I have done a script that collects the most important stuff from volume and disk WMI. its used with getting information from a Remote Desktop server where a lot of disks are mounted but can be hard to find who is using which disk. its using AD to query the user and connect it with the SID to find the file path. so its a matter of first collecting all the data from the different disk commands and then combine the outputs. the most important command to bind disk data with volume data is the get-partition that shows deviceid
Function Get-VHDMount {
[cmdletbinding()]
Param(
[Parameter(Position=0,ValueFromPipeline=$True)]
[ValidateNotNullorEmpty()]
[OBJECT[]]$Computername,
[STRING]$RDSPATH = '\\rdsprofiles'
)
foreach ($computer in $Computername) {
$RDSItems = (Get-ChildItem $RDSPATH -Recurse -Filter *.vhdx)
$VolumeInfo = invoke-command -ComputerName $computer -scriptblock {Get-Volume | select *}
$VHDMountInfo = Get-WmiObject Win32_Volume -ComputerName $computer |where Label -eq 'user Disk'
$partitioninfo = invoke-command -ComputerName $computer -scriptblock {Get-Partition | Select-Object DiskNumber, #{n='VolumeID';e={$_.AccessPaths | Where-Object { $_ -like '\\?\volume*' }}}}
foreach ($VHDmount in $VHDMountInfo) {
$adinfo = Get-ADUser ($VHDmount.name | Split-Path -Leaf)
[PSCUSTOMOBJECT]#{
Computername = $computer
username = $VHDmount.name | Split-Path -Leaf
displayname = $adinfo.name
SID = $adinfo.SID
deviceid = $VHDmount.deviceid
capacity = ([MATH]::ROUND(($VHDmount.capacity) / 1gb))
HealthStatus = ($VolumeInfo | where ObjectId -eq ($VHDmount.deviceid)).HealthStatus
DiskNumber = ($partitioninfo | where Volumeid -eq ($VHDmount.deviceid)).DiskNumber
Path = ($RDSItems | where fullname -like "*$($adinfo.SID)*").FullName
}
}
}
}