I found this post on Superuser,
And I’ve been using a modified version of the script in that post to effectively list all drives and various information:
function Get-AllDriveInfo {
$signature =
@'
[DllImport("kernel32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetVolumePathNamesForVolumeNameW([MarshalAs(UnmanagedType.LPWStr)] string lpszVolumeName,
[MarshalAs(UnmanagedType.LPWStr)] [Out] StringBuilder lpszVolumeNamePaths, uint cchBuferLength,
ref UInt32 lpcchReturnLength);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr FindFirstVolume([Out] StringBuilder lpszVolumeName,
uint cchBufferLength);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool FindNextVolume(IntPtr hFindVolume, [Out] StringBuilder lpszVolumeName, uint cchBufferLength);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, int ucchMax);
'@;
Add-Type -MemberDefinition $signature -Name Win32Utils -Namespace PInvoke -Using PInvoke, System.Text;
[UInt32] $lpcchReturnLength = 0;
[UInt32] $Max = 65535
$sbVolumeName = New-Object System.Text.StringBuilder($Max, $Max)
$sbPathName = New-Object System.Text.StringBuilder($Max, $Max)
$sbMountPoint = New-Object System.Text.StringBuilder($Max, $Max)
[IntPtr] $volumeHandle = [PInvoke.Win32Utils]::FindFirstVolume($sbVolumeName, $Max)
do {
$volume = $sbVolumeName.toString()
$unused = [PInvoke.Win32Utils]::GetVolumePathNamesForVolumeNameW($volume, $sbMountPoint, $Max, [Ref] $lpcchReturnLength);
$ReturnLength = [PInvoke.Win32Utils]::QueryDosDevice($volume.Substring(4, $volume.Length - 1 - 4), $sbPathName, [UInt32] $Max);
if ($ReturnLength) {
$DriveLetter = ($sbMountPoint.toString() -replace ':\','')
$VolumeData = Get-Volume -UniqueId $volume | Select-Object *
$PartitionData = Get-Partition -DriveLetter $DriveLetter | Select-Object *
[PSCustomObject]@{
DriveLetter = $DriveLetter
DevicePath = $sbPathName.ToString()
DiskNumber = $PartitionData.DiskNumber
HealthStatus = $VolumeData.HealthStatus
DriveType = $VolumeData.DriveType
FileSystem = $VolumeData.FileSystemType
AllocationUnitSize = $VolumeData.AllocationUnitSize
FriendlyLabel = $VolumeData.FileSystemLabel
Capacity = Format-Bytes -Bytes $VolumeData.Size
RemainingSpace = Format-Bytes -Bytes $VolumeData.SizeRemaining
VolumeName = $volume
GptType = $PartitionData.GptType
GUID = $PartitionData.Guid
IsActive = $PartitionData.IsActive
IsBoot = $PartitionData.IsBoot
IsDAX = $PartitionData.IsDAX
IsHidden = $PartitionData.IsHidden
IsOffline = $PartitionData.IsOffline
IsReadOnly = $PartitionData.IsReadOnly
IsShadowCopy = $PartitionData.IsShadowCopy
IsSystem = $PartitionData.IsSystem
MbrType = $PartitionData.MbrType
Offset = $PartitionData.Offset
}
} else {
Write-Output "No mountpoint found for: " + $volume
}
} while ([PInvoke.Win32Utils]::FindNextVolume([IntPtr] $volumeHandle, $sbVolumeName, $Max));
}
Get-AllDriveInfo
But what I really want now is to create a function that lists data only for a passed in drive (Either in drive letter format, or DevicePath format (DeviceHarddiskvolumeX
).
The code is quite a bit over my head, so I’m hoping someone can point me in the right direction. The idea is:
function Get-SpecificDriveInfo {
param (
[Parameter(Mandatory,ParameterSetName="DriveLetter")]
$DriveLetter,
[Parameter(Mandatory,ParameterSetName="DevicePath")]
$DevicePath
)
... Code to isolate the drive and print information.
}
# Usage:
Get-SpecificDriveInfo -DevicePath 'DeviceHarddiskVolume3'
Get-SpecificDriveInfo -DriveLetter 'C'
I know I’m asking for quite a bit of hand-holding but I just can’t wrap my head around some of the more advanced PInvoke.Win32Utils
functions and how they work.
Any help would be extremely appreciated!