当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 扩展 PowerShell PSDrive

作者:精品下载站 日期:2024-12-14 08:04:08 浏览:12 分类:玩电脑

扩展 PowerShell PSDrive


昨天我分享了一些用于管理 PSDrive 分配的 PowerShell 代码。我的代码在我的环境中适用于我。但这并不意味着它一定适合您和您的环境。有很多方法可以使用 PowerShell 来实现与我的代码相同的结果。在查看别人的代码时,您应该始终牢记这一点。但有足够的警告。在上一篇文章中,我向您开玩笑说 PSDrive 还有更多工作要做。今天我们就来看一下。

格式扩展

现在,您应该知道我是自定义格式的忠实粉丝。它节省了时间,并允许我以满足特定需求的格式查看信息。格式化扩展需要 XML 文件,但如果您已经阅读我的文章一段时间了,您就会知道我的 New-PSFormatXML 函数,它是 PSScriptTools 模块的一部分。我使用此命令为 PowerShell PSDrive 添加一些自定义视图。

当您运行 Get-PSDrive 时,PowerShell 使用名为 Drive 的默认视图格式化结果。我添加了几个新的表格视图。其中之一显示按提供商分组的 PSDrive。

[玩转系统] 扩展 PowerShell PSDrive

为了正确分组,您需要记住对 Provider 属性进行排序。或者使用 Get-PSDrive 获得更详细的信息。

[玩转系统] 扩展 PowerShell PSDrive

信息视图类似,但不包括提供者。

[玩转系统] 扩展 PowerShell PSDrive

获取文件系统驱动器

当我致力于这些扩展时,我意识到文件系统 PSDrive 对我来说更有价值。一直让我烦恼的一件事是我获取大小和使用信息,即使是指向文件夹的 PSDrive。

[玩转系统] 扩展 PowerShell PSDrive

我想要更好的东西。这不仅仅意味着格式扩展。我自己写了命令。

#requires -version 5.1

Function Get-FileSystemDrive {
    [cmdletbinding()]
    [OutputType("PSFileSystemDrive")]
    [alias("gfsd")]
    Param(
        [Parameter(HelpMessage = " Specifies, as a string array, the name or name of FileSystem PSDrives. Type the drive name or letter without a colon (:)")]
        [string[]]$Name
    )
    Begin {
        Write-Verbose "[$((Get-Date).TimeofDay) BEGIN  ] Starting $($myinvocation.mycommand)"
    } #begin

    Process {
        Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Getting FileSystem PSDrives"
        Try {
            $drives = Get-PSDrive @PSBoundParameters -PSProvider FileSystem -ErrorAction Stop
        }
        Catch {
            Throw $_
        }

        #create a custom object from the drive information
        if ($drives) {
            Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Found $($drives.count) FileSystem PSDrives"
            foreach ($drive in $drives) {
                #only get size information for root drives
                #need to account for non-Windows systems
                if ($drive.root -match "^(([A-Za-]:)\|\/)$") {
                    $info = [system.io.driveinfo]::new($drive.root)
                    if ($info.DriveType -eq 'Fixed') {
                        Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Getting root drive detail for $($info.name)"
                        $Free = $info.AvailableFreeSpace
                        $Used = $info.TotalSize - $info.AvailableFreeSpace
                        $Format = $info.DriveFormat
                        $Size = $info.totalSize
                        $IsPhysical = $True
                    }
                    else {
                        $Free = $null
                        $Used = $null
                        $Format = $Null
                        $Size = $null
                        $IsPhysical = $False
                    }
                }
                else {
                    $Free = $null
                    $Used = $null
                    $Format = $Null
                    $Size = $Nuyll
                    $IsPhysical = $False
                }
                [PSCustomObject]@{
                    PSTypeName      = "PSFileSystemDrive"
                    Name            = $drive.Name
                    Root            = $drive.Root
                    CurrentLocation = $drive.CurrentLocation
                    Description     = $drive.Description
                    Free            = $free
                    Used            = $used
                    Size            = $Size
                    Format          = $Format
                    IsPhysical      = $IsPhysical
                }
            }
        }

    } #process

    End {
        Write-Verbose "[$((Get-Date).TimeofDay) END    ] Ending $($myinvocation.mycommand)"

    } #end

} #close Get-FileSystemDrive

该函数是 Get-PSDrive 的包装器,仅返回文件系统驱动器。对于每个驱动器,我使用 PSFileSystemDrive 类型名创建自己的自定义对象。我需要一个独特的类型名称来用于即将到来的自定义格式和类型扩展。自定义对象可以更轻松地区分根物理驱动器(如 C: 和 D:)与 T(如 T)到 C:\Training 的映射。

在与该函数相同的文件中,我还定义了一个自定义类型扩展来定义脚本属性。

#add a script property to the custom object
$value = {
    if ($this.IsPhysical) {
        ($this.used/$this.size)*100
    }
    else {
        $Null
    }
}
Update-TypeData -TypeName 'PSFileSystemDrive' -MemberType ScriptProperty -MemberName Utilization -Value $value -force

如果 PSDrive 是物理驱动器,我会计算利用率百分比。当我定义对象时,我可以将其设置为静态属性。是的,我可以将自定义对象定义为 PowerShell 类。我仍然可能会这样做,因为在写这篇文章时我得到了其他想法。但现在,这就是我所拥有的。

我还使用 New-PSFormatXML 定义默认格式化视图。

[玩转系统] 扩展 PowerShell PSDrive

我发现这个输出更加简洁和有意义。请注意,我仅获取物理驱动器的大小和使用信息。我的格式 ps1xml 文件还使用脚本块和 ANSI 序列以颜色显示使用百分比。如果百分比为 90 或以上,则会显示为红色。不过,如果您使用的是 Windows 终端,则颜色可能会略有不同,具体取决于您的配色方案。

我还创建了第二个视图,称为“状态”,它最适合物理驱动器。

[玩转系统] 扩展 PowerShell PSDrive

该视图没有 ANSI 突出显示以供使用,但您当然可以添加它。

所有类型扩展都在同一个文件中。

<!--
Format type data generated 09/22/2021 09:13:30 by PROSPERO\Jeff

This file was created using the New-PSFormatXML command that is part
of the PSScriptTools module.

https://github.com/jdhitsolutions/PSScriptTools
-->
<Configuration>
  <ViewDefinitions>
    <View>
      <!--Created 09/22/2021 09:13:30 by PROSPERO\Jeff-->
      <Name>provider</Name>
      <ViewSelectedBy>
        <TypeName>System.Management.Automation.PSDriveInfo</TypeName>
      </ViewSelectedBy>
      <GroupBy>
        <ScriptBlock>$_.provider.Name</ScriptBlock>
        <Label>Provider</Label>
      </GroupBy>
      <TableControl>
        <!--Delete the AutoSize node if you want to use the defined widths.
        <AutoSize />-->
        <TableHeaders>
          <TableColumnHeader>
            <Label>Name</Label>
            <Width>12</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Root</Label>
            <Width>45</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>CurrentLocation</Label>
            <Width>20</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Description</Label>
          </TableColumnHeader>
        </TableHeaders>
        <TableRowEntries>
          <TableRowEntry>
            <Wrap />
            <TableColumnItems>
              <TableColumnItem>
                <PropertyName>Name</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Root</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>CurrentLocation</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Description</PropertyName>
              </TableColumnItem>
            </TableColumnItems>
          </TableRowEntry>
        </TableRowEntries>
      </TableControl>
    </View>
    <View>
      <!--Created 09/22/2021 11:15:30 by PROSPERO\Jeff-->
      <Name>info</Name>
      <ViewSelectedBy>
        <TypeName>System.Management.Automation.PSDriveInfo</TypeName>
      </ViewSelectedBy>
      <TableControl>
        <!--Delete the AutoSize node if you want to use the defined widths.-->
        <AutoSize />
        <TableHeaders>
          <TableColumnHeader>
            <Label>Name</Label>
            <Width>7</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Root</Label>
            <Width>7</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>CurrentLocation</Label>
            <Width>18</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Description</Label>
            <Width>14</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
        </TableHeaders>
        <TableRowEntries>
          <TableRowEntry>
            <Wrap />
            <TableColumnItems>
              <TableColumnItem>
                <PropertyName>Name</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Root</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>CurrentLocation</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Description</PropertyName>
              </TableColumnItem>
            </TableColumnItems>
          </TableRowEntry>
        </TableRowEntries>
      </TableControl>
    </View>
    <View>
      <!--Created 09/22/2021 10:02:46 by PROSPERO\Jeff-->
      <Name>default</Name>
      <ViewSelectedBy>
        <TypeName>PSFileSystemDrive</TypeName>
      </ViewSelectedBy>
      <TableControl>
        <!--Delete the AutoSize node if you want to use the defined widths.-->
        <AutoSize />
        <TableHeaders>
          <TableColumnHeader>
            <Label>Name</Label>
            <Width>7</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Root</Label>
            <Width>7</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Current</Label>
            <Width>18</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>SizeGB</Label>
            <Width>15</Width>
            <Alignment>right</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>PctUsed</Label>
            <Width>21</Width>
            <Alignment>right</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Format</Label>
            <Width>9</Width>
            <Alignment>right</Alignment>
          </TableColumnHeader>
        </TableHeaders>
        <TableRowEntries>
          <TableRowEntry>
            <TableColumnItems>
              <TableColumnItem>
                <PropertyName>Name</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Root</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>CurrentLocation</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <ScriptBlock>
                  if ($_.size) {
                    $_.Size/1GB -AS [int]
                  }
                  else {
                    $null
                  }
                  </ScriptBlock>
              </TableColumnItem>
              <TableColumnItem>
                <ScriptBlock>
                 if ($_.Utilization) {
                    <!-- display using ANSI-->
                    if ($host.name -match "console|code|ServerRemoteHost") {
                      $value = [math]::Round($_.Utilization,2)
                      Switch ($value) {
                        {$_ -ge 90} {
                          <!--red-->
                          "$([char]27)[90m$value$([char]27)[0m"
                        }
                        {$_ -ge 75} {
                          <!--yellow-->
                          "$([char]27)[38;5;227m$value$([char]27)[0m"
                        }
                        {$_ -ge 50} {
                          <!--purple-->
                          "$([char]27)[95m$value$([char]27)[0m"
                        }
                        default {
                          <!--green-->
                          "$([char]27)[92m$value$([char]27)[0m"
                        }
                      }
                    }
                    else {
                     [math]::Round($_.Utilization,2)
                    }
                  }
                  else {
                    $null
                  }
                </ScriptBlock>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Format</PropertyName>
              </TableColumnItem>
            </TableColumnItems>
          </TableRowEntry>
        </TableRowEntries>
      </TableControl>
    </View>
    <View>
      <!--Created 09/22/2021 12:39:34 by PROSPERO\Jeff-->
      <Name>status</Name>
      <ViewSelectedBy>
        <TypeName>PSFileSystemDrive</TypeName>
      </ViewSelectedBy>
      <GroupBy>
        <ScriptBlock>
        <!--display name using ANSI if supported-->
        if ($host.name -match "console|code|ServerRemoteHost") {
          $n = "$([char]27)[92m$($_.Name)$([char]27)[0m"
        }
        else {
          $n = $_.name
        }
        "{0}`n   Root: {1}" -f $n,$_.Root
        </ScriptBlock>
        <Label>Name</Label>
      </GroupBy>
      <TableControl>
        <!--Delete the AutoSize node if you want to use the defined widths.-->
        <AutoSize />
        <TableHeaders>
          <TableColumnHeader>
            <Label>CurrentLocation</Label>
            <Width>18</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>SizeGB</Label>
            <Width>7</Width>
            <Alignment>right</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>FreeGB</Label>
            <Width>7</Width>
            <Alignment>Right</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Utilization</Label>
            <Width>20</Width>
            <Alignment>right</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Description</Label>
          </TableColumnHeader>
        </TableHeaders>
        <TableRowEntries>
          <TableRowEntry>
            <Wrap />
            <TableColumnItems>
              <TableColumnItem>
                <PropertyName>CurrentLocation</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <ScriptBlock>
                if ($_.IsPhysical) {
                  $_.Size/1GB -as [int]
                }
                else {
                  $null
                }
                </ScriptBlock>
              </TableColumnItem>
              <TableColumnItem>
                <ScriptBlock>
                if ($_.IsPhysical) {
                  $_.Free/1GB -as [int]
                }
                else {
                  $null
                }
                </ScriptBlock>
              </TableColumnItem>
              <TableColumnItem>
                <ScriptBlock>
                if ($_.IsPhysical) {
                  [math]::Round($_.Utilization,2)
                  }
                else {
                  $null
                }
                </ScriptBlock>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Description</PropertyName>
              </TableColumnItem>
            </TableColumnItems>
          </TableRowEntry>
        </TableRowEntries>
      </TableControl>
    </View>
  </ViewDefinitions>
</Configuration>

在定义该函数的文件中,我添加以下代码片段:

Update-FormatData $psscriptroot\PSDriveInfo.format.ps1xml

所有文件都位于同一目录中,这就是我使用 $PSScriptRoot 的原因。

现在我有了命令和选项,可以让我的工作变得更轻松。当然,我仍然可以使用像 Get-Volume 这样的命令。或者我可以使用我自己的命令(它有一个定义的别名)。

[玩转系统] 扩展 PowerShell PSDrive

我希望你能抓住代码并使用它。这是改进 PowerShell 脚本编写的好方法。玩得开心!

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯