[玩转系统] 解决 PowerShell 对象时代挑战 - 第 1 部分
作者:精品下载站 日期:2024-12-14 07:58:54 浏览:14 分类:玩电脑
解决 PowerShell 对象时代挑战 - 第 1 部分
几周前,Iron Scripter 网站发布了一个有趣的挑战,关于编写一个通用函数来获取对象的年龄。我们在 PowerShell 中处理的许多事物都有“年龄”,例如文件、进程甚至 AD 组和用户。我认为这是一个特别有用的练习,因为它迫使您理解“管道中的对象”的 PowerShell 范例。
方法
我总是发现尝试可视化管道过程很有帮助。如果没有别的事,你需要能够口头描述你的命令将要做什么。如果你不能,你将很难编写代码。我知道在检索创建时间时,我必须至少确定对象的一个属性以供使用。因为挑战的一部分是获得所有已处理对象的平均年龄,所以我知道我必须在 End 脚本块中完成大部分工作。以下是我的口述:
初始化一个数组来保存传入的对象。当对象通过管道传入函数时,将每个函数添加到临时数组中。处理完所有内容后,计算平均年龄。对于临时数组中的每个对象,创建一个具有计算时间跨度的自定义结果。
这是一个不错的起点。
概述代码
在代码中勾画出这个我想出了这个。
Begin {
#initialize holding array
}
Process {
foreach ($item in $input) {
#add each item to the array
}
}
End {
#calculate average age for all items in holding array
$Age = #code
foreach ($object in $array) {
#create custom object
[pscustomobject]@{
Created = $object.$CreationProperty
Modified = $object.$ChangeProperty
Age = $Age
Average = If ($Age -gt $Avg) {"Above"} else {"Below"}
}
}
}
我希望这种情况能够改变,但这给了我一个很好的起点。对于参数,我可以获取任何类型对象的输入。但我必须依靠用户来了解创建属性的用途,以及指示对象上次更改时间的可选属性。对象可能没有“已更改”属性,因此我将默认使用创建属性。我还希望用户能够在输出中指定他们想要的其他参数。
Param(
[Parameter(Mandatory, ValueFromPipeline)]
[ValidateNotNullorEmpty()]
[object[]]$InputObject,
[Parameter(Mandatory, Position = 0)]
[string]$CreationProperty,
[Parameter(Position = 1)]
[string]$ChangeProperty,
[object[]]$Properties = @("Name")
)
这似乎是可以管理的。
通常,我会简单地初始化一个空数组。但为了让事情变得更有趣,我将使用通用列表对象。
$all = [System.Collections.Generic.List[object]]::new()
这种类型的对象应该具有更好的性能。作为快速测试,这段代码
measure-command {
$all = [System.Collections.Generic.List[object]]::new()
dir c:\scripts -file -Recurse | foreach-object { $all.Add($_) }
}
添加近 7900 个文件花了 2.95 秒。与“传统”方法相比。
measure-command {
$all = @()
dir c:\scripts -file -Recurse | foreach-object { $all+=$_ }
}
耗时 5.5 秒。我不想分心讨论这两种方法的优点,但对于这个解决方案,我将使用通用列表。我基本上将使用相同的模式:对于每个通过管道传入的对象,将其添加到列表中。
在“结束”块中,我现在可以处理所有对象。首先,我需要为每个对象构建一个创建年龄时间跨度的数组。
$allTimeSpans = $all | ForEach-Object {
Try {
$X = $_
New-TimeSpan -start $_.$creationProperty -end $Now -ErrorAction Stop
}
Catch {
Write-Warning "Failed to get $CreationProperty value. $($_.exception.message)"
Write-Warning ($X | Out-String)
}
} #foreach
然后我可以测量该集合并生成平均时间跨度。我将使用 TotalSeconds。
$avg = New-TimeSpan -seconds ($allTimeSpans | Measure-Object -Property TotalSeconds -average).Average
我将使用该值作为每个对象的创建年龄的比较,以便我可以指示它是高于还是低于平均水平。
对于列表中的每个文件,我将创建一个 [ordered] 哈希表。我这样做是因为我想要至少有一些输出结构。
foreach ($item in $all) {
$Age = New-TimeSpan -end $Now -Start ($item.$creationProperty)
$tmpHash = [ordered]@{
Created = $item.$CreationProperty
Modified = $item.$ChangeProperty
Age = $Age
Average = If ($Age -gt $Avg) {"Above"} else {"Below"}
}
接下来,我需要考虑额外的属性。我还决定支持哈希表,就像您在 Select-Object 中使用的那样。
foreach ($prop in $Properties) {
if ($prop.gettype().name -eq 'hashtable') {
Write-Verbose "[END ] Expanding hashtable"
$custom = $item | Select-object -property $prop
$prop = $custom.psobject.properties.Name
$val = $custom.psobject.properties.Value
}
else {
$val = $item.$prop
}
#shorten the value for the verbose message
if ($VerbosePreference -eq "Continue") {
$valtest = ($val | Out-String).trim()
if ($valtest.length -ge 19) {
$valstring = "{0}.." -f $valtest.Substring(0, 19)
}
else {
$valstring = $valtest
}
}
Write-Verbose "[END ] Adding Property: $prop Value: $valstring"
$tmpHash.Add($prop, $val)
} #foreach property
其要点是获取每个对象的属性值并将其作为新元素添加到临时哈希表中。我也喜欢使用详细消息,在测试中我决定缩短值文本以防止详细消息换行。纯粹是化妆品。
每个对象的最后一步是创建自定义对象。
New-Object -TypeName PSObject -property $tmpHash
附加功能
我决定用这个功能来一点额外的乐趣。首先,显示结果后,我使用 Write-Host 显示平均总体创建年龄的彩色摘要。
Write-Host "`n$([char]0x1b)[1;38;5;154mAverage Creation Age Overall : $avg"
我什至使用 ANSI 转义序列以自定义颜色对输出进行着色。为什么要写主机?函数应该只将一种类型的对象写入管道,我的已经是了。我不想让它也写一个字符串。我本可以将此信息作为属性添加到每个对象,但决定简单地将信息写入控制台而不是管道。此转义序列适用于 Windows PowerShell 和 PwoerShell 7。
我想尝试的另一件事是控制台风格的进度指示器。我想要有一些东西来表明项目正在处理并添加到列表中。再次,一点 ANSI 的魔力可以拯救你。
在 Begin 块中,我定义了一个字符数组和一个计数器。
$ch = @("|", "/", "-", "\", "|", "/", "-")
$c = 0
在处理每个项目时,我使用 Write-Host 和 ANSI 序列来确保每行都写入相同的位置。
if (-Not ($VerbosePreference -eq "Continue")) {
if ($c -ge $ch.count) {
$c = 0
}
Write-Host "$([char]0x1b)[1EProcessing $($ch[$c])$([char]0x1b)[0m" -ForegroundColor cyan -NoNewline
$c++
#adding an artificial sleep so the progress wheel looks like it is spinning
Start-Sleep -Milliseconds 10
}
最终结果是一个小旋转器。我添加了人工睡眠以使其看起来更好。我只在不使用 -Verbose 时使用进度微调器,因为详细消息列表会将微调器很快移出屏幕。
功能齐全
这是完整的功能。我不会在 PowerShell ISE 中很好地显示 ANSI 序列。
Function Get-ObjectAge {
[cmdletbinding()]
[alias('goa')]
Param(
[Parameter(Mandatory, ValueFromPipeline)]
[ValidateNotNullorEmpty()]
[object[]]$InputObject,
[Parameter(Mandatory, Position = 0)]
[string]$CreationProperty,
[Parameter(Position = 1)]
[string]$ChangeProperty,
[object[]]$Properties = @("Name")
)
Begin {
Write-Verbose "[BEGIN ] Starting: $($MyInvocation.Mycommand)"
#create a list object to hold all incoming objects.
#this should perform slightly better than a traditional array
$all = [System.Collections.Generic.List[object]]::new()
#use the same date time for all timespan calculations
$Now = Get-Date
Write-Verbose "[BEGIN ] Using $NOW for timespan calculations"
Write-Verbose "[BEGIN ] Using $CreationProperty for CreationProperty"
#use $CreationProperty parameter value for Change property if latter is not specified
if (-Not $ChangeProperty) {
Write-Verbose "[BEGIN ] Using $CreationProperty for ChangeProperty"
$changeProperty = $CreationProperty
}
else {
Write-Verbose "[BEGIN ] Using $ChangeProperty for ChangeProperty"
}
#initialize counters and an array of characters to be using in a progress wheel
$i = 0
$ch = @("|", "/", "-", "\", "|", "/", "-")
$c = 0
} #begin
Process {
foreach ($object in $InputObject) {
$i++
#display a progress wheel if NOT using -Verbose
if (-Not ($VerbosePreference -eq "Continue")) {
if ($c -ge $ch.count) {
$c = 0
}
Write-Host "$([char]0x1b)[1EProcessing $($ch[$c])$([char]0x1b)[0m" -ForegroundColor cyan -NoNewline
$c++
#adding an artificial sleep so the progress wheel looks like it is spinning
Start-Sleep -Milliseconds 10
}
#add the incoming object to the list
$all.Add($object)
}
} #process
End {
Write-Verbose "[END ] Calculating average creation age for $($all.count) objects"
$allTimeSpans = $all | ForEach-Object {
Try {
$X = $_
New-TimeSpan -start $_.$creationProperty -end $Now -ErrorAction Stop
}
Catch {
Write-Warning "Failed to get $CreationProperty value. $($_.exception.message)"
Write-Warning ($X | Out-String)
}
} #foreach
#get the average creation age timespan
$avg = New-TimeSpan -seconds ($allTimeSpans | Measure-Object -Property TotalSeconds -average).Average
#create a result object for each processed object and save to an array
$results = foreach ($item in $all) {
$Age = New-TimeSpan -end $Now -Start ($item.$creationProperty)
$tmpHash = [ordered]@{
Created = $item.$CreationProperty
Modified = $item.$ChangeProperty
Age = $Age
Average = If ($Age -gt $Avg) {"Above"} else {"Below"}
}
#add user specified properties
foreach ($prop in $Properties) {
if ($prop.gettype().name -eq 'hashtable') {
Write-Verbose "[END ] Expanding hashtable"
$custom = $item | Select-object -property $prop
$prop = $custom.psobject.properties.Name
$val = $custom.psobject.properties.Value
}
else {
$val = $item.$prop
}
#shorten the value for the verbose message
if ($VerbosePreference -eq "Continue") {
$valtest = ($val | Out-String).trim()
if ($valtest.length -ge 19) {
$valstring = "{0}.." -f $valtest.Substring(0, 19)
}
else {
$valstring = $valtest
}
}
Write-Verbose "[END ] Adding Property: $prop Value: $valstring"
$tmpHash.Add($prop, $val)
} #foreach property
#create the object
New-Object -TypeName PSObject -property $tmpHash
} #foreach item
#display all the results at once
$results
#display a message about the average creation age
Write-Host "`n$([char]0x1b)[1;38;5;154mAverage Creation Age Overall : $avg"
Write-Verbose "[END ] Ending: $($MyInvocation.Mycommand)"
} #end
} #end function
想看看它的效果吗?该函数适用于文件。
让它变得更好
我有一个足够通用的函数,可以处理任何对象类型,假设它有一个反映它创建时间的属性。尽管这很好,但我知道它还可以更好。但我想我已经给了你足够玩一天的内容,所以我很快就会把增强版保存到另一天。
猜你还喜欢
- 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