[玩转系统] 使用 PowerShell 全面开放
作者:精品下载站 日期:2024-12-14 20:38:27 浏览:12 分类:玩电脑
使用 PowerShell 全面开放
几周前,发布了 Iron Scripter PowerShell 脚本挑战赛。挑战涉及广泛的目录列表。这总是让我想到“敞开心扉”,这让我想到了蔡斯的“敞开心扉”。 (我以前吹小号,Chase 是当时的乐队)。无论如何,解决这个挑战很可能涉及 Get-ChildItem 和 Format-Wide 的组合。这就是我的想法。
独立功能
我的第一个解决方案采用独立函数的形式。该函数的大部分参数与 Get-ChildItem 相同。但我还提供了一个参数,让用户指定在显示的 [] 部分中显示哪些数据。这是完整的功能,然后我会指出一些事情。
Function Show-DirectoryInfo {
#this version writes formatted data to the pipeline
[cmdletbinding()]
[alias("sw")]
Param(
[Parameter(Position = 0,HelpMessage = "Enter a file system path")]
[ValidateScript({( Test-Path $_ ) -AND ((Get-Item $_).psprovider.name -eq "FileSystem")})]
[string]$Path = ".",
[Parameter(Position = 1,HelpMessage = "What detail do you want to see? Size or Count of files?")]
[ValidateSet("Size", "Count")]
[string]$Detail = "Count",
[switch]$Recurse,
[Int32]$Depth
)
DynamicParam {
if ($Detail -eq "Size") {
#define a parameter attribute object
$attributes = New-Object System.Management.Automation.ParameterAttribute
$attributes.HelpMessage = "Enter a unit of measurement: KB, MB, GB Bytes."
#define a collection for attributes
$attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
$attributeCollection.Add($attributes)
#define an alias
$alias = New-Object System.Management.Automation.AliasAttribute -ArgumentList "as"
$attributeCollection.Add($alias)
#add a validateion set
$set = New-Object -type System.Management.Automation.ValidateSetAttribute -ArgumentList ("bytes", "KB", "MB", "GB")
$attributeCollection.add($set)
#define the dynamic param
$dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter("Unit", [string], $attributeCollection)
$dynParam1.Value = "Bytes"
#create array of dynamic parameters
$paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
$paramDictionary.Add("Unit", $dynParam1)
#use the array
return $paramDictionary
} #if
} #dynamic parameter
Begin {
Write-Verbose "Starting $($myinvocation.MyCommand)"
#set a default size unit
if ($Detail -eq 'Size' -AND (-not $PSBoundParameters.ContainsKey("unit"))) {
$PSBoundParameters.Add("Unit", "bytes")
}
#these internal helper functions could be combined but I'll keep them
#separate for the sake of clarity.
function _getCount {
[cmdletbinding()]
Param([string]$Path)
(Get-ChildItem -Path $path -File).count
}
function _getSize {
[cmdletbinding()]
Param([string]$Path, [string]$Unit)
$sum = (Get-ChildItem $path -File | Measure-Object -Sum -Property length).sum
#write-verbose "detected $unit"
Switch ($Unit) {
"KB" { "$([math]::round($sum/1KB,2))KB" }
"MB" { "$([math]::round($sum/1MB,2))MB" }
"GB" { "$([math]::round($sum/1GB,2))GB" }
Default { $sum }
}
}
Write-Verbose "PSBoundParameters"
Write-Verbose ($PSBoundParameters | Out-String)
#build a hashtable of parameters to splat to Get-ChildItem
$gciParams = @{
Path = $Path
Directory = $True
}
if ($PSBoundParameters["Depth"]) {
$gciParams.Add("Depth", $PSBoundParameters["Depth"])
}
if ($PSBoundParameters["Recurse"]) {
$gciParams.Add("Recurse", $PSBoundParameters["Recurse"])
}
} #begin
Process {
Write-Verbose "Processing $(Convert-Path $Path)"
$directories = Get-ChildItem @gciParams
#this code could be consolidated using techniques like splatting. This version emphasizes clarity.
if ($Detail -eq "count") {
Write-Verbose "Getting file count"
if ($Recurse) {
$directories | Get-ChildItem -Recurse -Directory | Format-Wide -Property { "$($_.name) [$( _getCount $_.fullname)]" } -AutoSize -GroupBy @{Name = "Path"; Expression = { $_.Parent }}
}
else {
$directories | Format-Wide -Property { "$($_.name) [$( _getCount $_.fullname)]" } -AutoSize -GroupBy @{Name="Path";Expression={$_.Parent}}
}
}
else {
Write-Verbose "Getting file size in $($PSBoundParameters['Unit']) units"
if ($Recurse) {
$directories | Get-ChildItem -Recurse -Directory | Format-Wide -Property { "$($_.name) [$( _getsize -Path $_.fullname -unit $($PSBoundParameters['Unit']))]" } -AutoSize -GroupBy @{Name = "Path"; Expression = { $_.Parent }}
}
else {
$directories | Format-Wide -Property { "$($_.name) [$( _getsize -path $_.fullname -unit $($PSBoundParameters['Unit']))]" } -AutoSize -GroupBy @{Name = "Path"; Expression = { $_.Parent }}
}
}
} #Process
End {
Write-Verbose "Ending $($myinvocation.MyCommand)"
}
}
我的函数包含解决一些挑战奖励元素的代码。首先,我使用参数验证来确保路径存在并且是文件系统路径。
[Parameter(Position = 0,HelpMessage = "Enter a file system path")]
[ValidateScript({( Test-Path $_ ) -AND ((Get-Item $_).psprovider.name -eq "FileSystem")})]
[string]$Path = ".",
我一开始有 2 个 ValidateScript 设置,但决定将它们组合起来。 Detail 参数是使用 ValidateSet 属性定义的。
[Parameter(Position = 1,HelpMessage = "What detail do you want to see? Size or Count of files?")]
[ValidateSet("Size", "Count")]
[string]$Detail = "Count",
现在是有趣的部分。我想要一种方法让用户格式化总文件大小,即以 KB 为单位(如果他们愿意的话)。但只有当用户选择使用“详细信息”参数的“大小”值时,才需要执行此操作。我选择使用动态参数。
DynamicParam {
if ($Detail -eq "Size") {
#define a parameter attribute object
$attributes = New-Object System.Management.Automation.ParameterAttribute
$attributes.HelpMessage = "Enter a unit of measurement: KB, MB, GB Bytes."
#define a collection for attributes
$attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
$attributeCollection.Add($attributes)
#define an alias
$alias = New-Object System.Management.Automation.AliasAttribute -ArgumentList "as"
$attributeCollection.Add($alias)
#add a validateion set
$set = New-Object -type System.Management.Automation.ValidateSetAttribute -ArgumentList ("bytes", "KB", "MB", "GB")
$attributeCollection.add($set)
#define the dynamic param
$dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter("Unit", [string], $attributeCollection)
$dynParam1.Value = "Bytes"
#create array of dynamic parameters
$paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
$paramDictionary.Add("Unit", $dynParam1)
#use the array
return $paramDictionary
} #if
} #dynamic parameter
仅当详细参数为“Size”时,此参数才存在。该代码创建一个动态参数作为 Unit ,别名为 As。它还定义了一个验证集。
该函数的主要部分使用适当的参数调用 Get-ChildItem,然后使用 Format-Wide 格式化结果,并在父路径上自动调整大小和分组。
这是默认行为。
或者使用动态参数。
这可行,但存在许多潜在的缺点。
首先,动态参数有问题。默认情况下,它不会显示在命令帮助中。
尽管 PSReadline 和制表符完成应该检测到它。我不太喜欢动态参数,尤其是当有其他选项时。在这个函数中,我可以定义多个参数集。一种用于计数,另一种用于尺寸。如果我要继续使用这个功能,我就会做出改变。我在这个例子中保留了动态参数,因为我经常被问到这个问题,这里有一个很好的工作演示。
这种方法的另一个问题是函数中包含格式化。这意味着该函数的输出是格式范围指令,而不是“真实”对象。我唯一能做的就是查看输出或将其通过管道传输到输出打印机或输出文件。您几乎不想在函数中包含 Format 命令。这就是我使用 Show 作为命令动词的原因之一。我没有得到什么东西,我只是展示它。
使用 PowerShell 类
由于我正在编写一个函数,因此它需要将一个对象写入管道。我可以将函数输出传输到 Format-Wide 以获得所需的结果。我本可以在函数中使用 Select-Object 或 [pscustomobject] 类型,但我选择了 PowerShell 类定义。
Class DirectoryStat {
[string]$Name
[string]$Path
[int64]$FileCount
[int64]$FileSize
[string]$Parent
[string]$Computername = [System.Environment]::MachineName
} #close class definition
该类没有任何方法或特殊的构造函数。然后我编写了一个函数来使用这个类。
Function Get-DirectoryInfo {
[cmdletbinding()]
[alias("dw")]
[OutputType("DirectoryStat")]
Param(
[Parameter(Position = 0)]
[ValidateScript( { (Test-Path $_ ) -AND ((Get-Item $_).psprovider.name -eq "FileSystem") })]
[string]$Path = ".",
[switch]$Recurse,
[int32]$Depth
)
Begin {
Write-Verbose "Starting $($myinvocation.MyCommand)"
#initialize a collection to hold the results
$data = [System.Collections.Generic.list[object]]::new()
function _newDirectoryStat {
[CmdletBinding()]
Param(
[Parameter(ValueFromPipelineByPropertyName, Mandatory)]
[string]$PSPath
)
Begin {}
Process {
$path = Convert-Path $PSPath
$name = Split-Path -Path $Path -Leaf
$stat = Get-ChildItem -Path $path -File | Measure-Object -Property Length -Sum
$ds = [DirectoryStat]::New()
$ds.Name = $name
$ds.Path = $Path
$ds.FileCount = $stat.Count
$ds.FileSize = $stat.Sum
$ds.Parent = (Get-Item -Path $path).Parent.FullName
$ds
}
end {}
}
Write-Verbose "PSBoundParameters"
Write-Verbose ($PSBoundParameters | Out-String)
#build a hashtable of parameters to splat to Get-ChildItem
$gciParams = @{
Path = $Path
Directory = $True
}
if ($PSBoundParameters["Depth"]) {
$gciParams.Add("Depth", $PSBoundParameters["Depth"])
}
if ($PSBoundParameters["Recurse"]) {
$gciParams.Add("Recurse", $PSBoundParameters["Recurse"])
}
} #begin
Process {
Write-Verbose "Processing $(Convert-Path $Path)"
$data.Add((Get-ChildItem @gciParams | _newDirectoryStat))
} #Process
End {
#pre-sort the data
$data | Sort-Object -Property Parent, Name
Write-Verbose "Ending $($myinvocation.MyCommand)"
}
}
正如您所看到的,该函数将一个对象写入管道,我可以根据需要对其进行格式化。
挑战在于以宽格式显示结果。正如您所看到的,这当然是可能的。但为了让这更容易,因为我使用的是自定义对象,所以我可以创建一个自定义格式文件。我使用 PSScriptTools 模块中的 New-PSFormatXML 创建一个默认视图,然后创建第二个命名视图。
dw | New-PSFormatXML -Path .\directorystat.format.ps1xml -Properties Name -GroupBy Parent -FormatType Wide
dw | New-PSFormatXML -Path .\directorystat.format.ps1xml -Properties Name -GroupBy Parent -FormatType Wide -append -ViewName sizekb
我的函数有一个别名 dw。我使用脚本块修改了该文件,以便默认视图是一个宽条目,并带有自定义显示,在括号中显示目录名称和文件计数。我还更新了 sizeKB 视图,以在方括号内显示以 KB 为单位的文件大小。我只需复制、粘贴和编辑即可获得更多视图。
我需要做的就是加载文件。
Update-FormatData .\directorystat.format.ps1xml
Get-FormatView 也是 PSScriptTools 模块的一部分。有了这个格式文件,我现在有了一个带有文件计数值的默认视图。
或者我可以说出其他宽广的观点。
如您所见,我在 ps1xml 文件中添加了 ANSI 转义序列。这应该适用于 Windows PowerShell 和 PowerShell 7。
<?xml version="1.0" encoding="UTF-8"?>
<!--
format type data generated 10/07/2020 12:20:03 by PROSPERO\Jeff
File created with New-PSFormatXML from the PSScriptTools module
which can be installed from the PowerShell Gallery
-->
<Configuration>
<ViewDefinitions>
<View>
<!--Created 10/07/2020 12:20:03 by PROSPERO\Jeff-->
<Name>default</Name>
<ViewSelectedBy>
<TypeName>DirectoryStat</TypeName>
</ViewSelectedBy>
<GroupBy>
<ScriptBlock>"$([char]0x1b)[1;93m$($_.Parent)$([char]0x1b)[0m"</ScriptBlock>
<Label>Path</Label>
</GroupBy>
<WideControl>
<AutoSize />
<WideEntries>
<WideEntry>
<WideItem>
<ScriptBlock>"$([char]0x1b)[92m{0}$([char]0x1b)[0m [{1}]" -f $_.Name,$_.filecount</ScriptBlock>
</WideItem>
</WideEntry>
</WideEntries>
</WideControl>
</View>
<View>
<!--Created 10/07/2020 12:23:20 by PROSPERO\Jeff-->
<Name>size</Name>
<ViewSelectedBy>
<TypeName>DirectoryStat</TypeName>
</ViewSelectedBy>
<GroupBy>
<ScriptBlock>"$([char]0x1b)[1;93m$($_.Parent)$([char]0x1b)[0m"</ScriptBlock>
<Label>Path</Label>
</GroupBy>
<WideControl>
<AutoSize />
<WideEntries>
<WideEntry>
<WideItem>
<ScriptBlock>"$([char]0x1b)[92m{0}$([char]0x1b)[0m [$([char]0x1b)[38;5;190m{1}$([char]0x1b)[0m]" -f $_.Name,$_.filesize</ScriptBlock>
</WideItem>
</WideEntry>
</WideEntries>
</WideControl>
</View>
<View>
<!--Created 10/07/2020 12:23:20 by PROSPERO\Jeff-->
<Name>sizekb</Name>
<ViewSelectedBy>
<TypeName>DirectoryStat</TypeName>
</ViewSelectedBy>
<GroupBy>
<ScriptBlock>"$([char]0x1b)[1;93m$($_.Parent)$([char]0x1b)[0m"</ScriptBlock>
<Label>Path</Label>
</GroupBy>
<WideControl>
<WideEntries>
<WideEntry>
<WideItem>
<ScriptBlock>"$([char]0x1b)[92m{0}$([char]0x1b)[0m [$([char]0x1b)[38;5;164m{1}KB$([char]0x1b)[0m]" -f $_.Name,([math]::Round($_.filesize/1KB,2))</ScriptBlock>
</WideItem>
</WideEntry>
</WideEntries>
</WideControl>
</View>
<View>
<!--Created 10/07/2020 12:23:20 by PROSPERO\Jeff-->
<Name>sizemb</Name>
<ViewSelectedBy>
<TypeName>DirectoryStat</TypeName>
</ViewSelectedBy>
<GroupBy>
<ScriptBlock>"$([char]0x1b)[1;93m$($_.Parent)$([char]0x1b)[0m"</ScriptBlock>
<Label>Path</Label>
</GroupBy>
<WideControl>
<WideEntries>
<WideEntry>
<WideItem>
<ScriptBlock>"$([char]0x1b)[92m{0}$([char]0x1b)[0m [$([char]0x1b)[38;5;147m{1}MB$([char]0x1b)[0m]" -f $_.Name,([math]::Round($_.filesize/1mb,2))</ScriptBlock>
</WideItem>
</WideEntry>
</WideEntries>
</WideControl>
</View>
</ViewDefinitions>
</Configuration>
这是我在使用 PowerShell 编写脚本时推荐的方法。让您的函数将对象写入管道。这是您的原始输出。然后根据需要使用 PowerShell 命令来操作和格式化数据。如果您知道需要某种默认格式,请创建一个 format.ps1xml 文件。
我意识到你们中的一些人仍在开始学习 PowerShell,这没关系。这就是 Iron Scripter 挑战背后的目的——测试和扩展你的技能。我希望您能尝试一下其他一些挑战。
猜你还喜欢
- 03-30 [玩转系统] 如何用批处理实现关机,注销,重启和锁定计算机
- 02-14 [系统故障] Win10下报错:该文件没有与之关联的应用来执行该操作
- 01-07 [系统问题] Win10--解决锁屏后会断网的问题
- 01-02 [系统技巧] Windows系统如何关闭防火墙保姆式教程,超详细
- 12-15 [玩转系统] 如何在 Windows 10 和 11 上允许多个 RDP 会话
- 12-15 [玩转系统] 查找 Exchange/Microsoft 365 中不活动(未使用)的通讯组列表
- 12-15 [玩转系统] 如何在 Windows 上安装远程服务器管理工具 (RSAT)
- 12-15 [玩转系统] 如何在 Windows 上重置组策略设置
- 12-15 [玩转系统] 如何获取计算机上的本地管理员列表?
- 12-15 [玩转系统] 在 Visual Studio Code 中连接到 MS SQL Server 数据库
- 12-15 [玩转系统] 如何降级 Windows Server 版本或许可证
- 12-15 [玩转系统] 如何允许非管理员用户在 Windows 中启动/停止服务
取消回复欢迎 你 发表评论:
- 精品推荐!
-
- 最新文章
- 热门文章
- 热评文章
[影视] 黑道中人 Alto Knights(2025)剧情 犯罪 历史 电影
[古装剧] [七侠五义][全75集][WEB-MP4/76G][国语无字][1080P][焦恩俊经典]
[实用软件] 虚拟手机号 电话 验证码 注册
[电视剧] 安眠书店/你 第五季 You Season 5 (2025) 【全10集】
[电视剧] 棋士(2025) 4K 1080P【全22集】悬疑 犯罪 王宝强 陈明昊
[软件合集] 25年6月5日 精选软件22个
[软件合集] 25年6月4日 精选软件36个
[短剧] 2025年06月04日 精选+付费短剧推荐33部
[短剧] 2025年06月03日 精选+付费短剧推荐25部
[软件合集] 25年6月3日 精选软件44个
[剧集] [央视][笑傲江湖][2001][DVD-RMVB][高清][40集全]李亚鹏、许晴、苗乙乙
[电视剧] 欢乐颂.5部全 (2016-2024)
[电视剧] [突围] [45集全] [WEB-MP4/每集1.5GB] [国语/内嵌中文字幕] [4K-2160P] [无水印]
[影视] 【稀有资源】香港老片 艺坛照妖镜之96应召名册 (1996)
[剧集] 神经风云(2023)(完结).4K
[剧集] [BT] [TVB] [黑夜彩虹(2003)] [全21集] [粤语中字] [TV-RMVB]
[实用软件] 虚拟手机号 电话 验证码 注册
[资源] B站充电视频合集,包含多位重量级up主,全是大佬真金白银买来的~【99GB】
[影视] 内地绝版高清录像带 [mpg]
[书籍] 古今奇书禁书三教九流资料大合集 猎奇必备珍藏资源PDF版 1.14G
[电视剧] [突围] [45集全] [WEB-MP4/每集1.5GB] [国语/内嵌中文字幕] [4K-2160P] [无水印]
[剧集] [央视][笑傲江湖][2001][DVD-RMVB][高清][40集全]李亚鹏、许晴、苗乙乙
[电影] 美国队长4 4K原盘REMUX 杜比视界 内封简繁英双语字幕 49G
[电影] 死神来了(1-6)大合集!
[软件合集] 25年05月13日 精选软件16个
[精品软件] 25年05月15日 精选软件18个
[绝版资源] 南与北 第1-2季 合集 North and South (1985) /美国/豆瓣: 8.8[1080P][中文字幕]
[软件] 25年05月14日 精选软件57个
[短剧] 2025年05月14日 精选+付费短剧推荐39部
[短剧] 2025年05月15日 精选+付费短剧推荐36部
- 最新评论
-
- 热门tag