如何创建一个接受DevicePath(\Device\Harddiskvolume3)或驱动器号(C)的函数,然后在Pwsh 7中输出指定信息?

问题描述 投票:0回答:1

我在超级用户上找到了这篇文章

我在那篇文章中使用了脚本的修改版本来有效地列出所有驱动器和各种信息:


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

但我现在真正想要的是创建一个函数,仅列出传入驱动器的数据(以驱动器号格式或 DevicePath 格式 (

\Device\HarddiskvolumeX
)。

代码有点超出我的理解,所以我希望有人能指出我正确的方向。这个想法是:

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 '\Device\HarddiskVolume3'
Get-SpecificDriveInfo -DriveLetter 'C'

我知道我需要相当多的帮助,但我就是无法理解一些更高级的

PInvoke.Win32Utils
功能及其工作原理。

任何帮助将不胜感激!

powershell drive
1个回答
0
投票

实际上,变化会很小:

function Get-SpecificDriveInfo {

    param (
        [Parameter(Mandatory,ParameterSetName="DriveLetter")]
        [String]$DriveLetter,

        [Parameter(Mandatory,ParameterSetName="DevicePath")]
        [String]$DevicePath
    )

    $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) {
            $Drive_Letter = ($sbMountPoint.toString() -replace ':\\','')
            $VolumeData = Get-Volume -UniqueId $volume | Select-Object *
            $PartitionData = Get-Partition -DriveLetter $DriveLetter | Select-Object *
            #my change
            if ((($Drive_Letter -eq $DriveLetter) -and ($PSBoundParameters.ContainsKey('DriveLetter'))) -or (($sbPathName.ToString() -eq $DevicePath)) -and ($PSBoundParameters.ContainsKey('DevicePath'))) {
                [PSCustomObject]@{
                    DriveLetter = $Drive_Letter
                    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));
}

# Usage:
Get-SpecificDriveInfo -DevicePath '\Device\HarddiskVolume3'
Get-SpecificDriveInfo -DriveLetter 'C'

我添加了一个比较块,用于检查是否给出了参数以及它等于什么。

© www.soinside.com 2019 - 2024. All rights reserved.