问题描述
我有各种各样的计算机,我正在编写一个 Powershell 脚本,该脚本将网络共享与服务器上的本地计算机驱动程序存储库一起安装,这些计算机驱动程序作为每台计算机的品牌和型号保存在它们自己的单独目录中(例如联想 E460、戴尔 Latitude E5450 等)。
这是我想要做的:
我想要获取计算机的信息(品牌和型号)并将其连接成一个字符串。然后我希望该字符串被引用到驱动程序目录的数组中,如果计算机 make + 型号匹配,我希望计算机下载该目录中的驱动程序。我来自 Web 开发背景,这里是我通常使用 JavaScript Array.prototype.filter()
方法过滤数组以将 $computer
与 $drivers
数组中的每个子项进行比较的地方。
$computer = (gwmi Win32_ComputerSystem).Manufacturer + " " + (dwmi Win32_ComputerSystem).Model
$drivers = Get-ChildItem \\zapp\pc\!Drivers
Powershell 实现此目的的最佳方法是什么? Powershell 是否有类似于 JavaScript 的过滤和比较数组方法?或者 Foreach
-match
或 -eq
是最有效的书写方式吗?
谢谢!
解决方法
你好,晚上好。
直到有人比我聪明得多(不会很长),我才能尝试为您指明正确的方向。
您实际上有多种选择。您可以使用依赖于 bool 的条件语句(布尔值 - 只是一种华丽的说法),以及 Where-Object
与一些运算符的结合。
让我先发布这个,这样它就不会在我身上崩溃(破裂了我的屏幕并且它的表现很不稳定)。我们将从 Switch
声明开始。如果满足条件,就做点什么。
$computer = (gwmi Win32_ComputerSystem).Manufacturer + " " + (gwmi Win32_ComputerSystem).Model
$drivers = Get-ChildItem \\zapp\pc\!Drivers | Select-Object -ExpandProperty Name
Switch ($drivers){
"$computer" {"Found: $_" }
}
我回来了! 所以,回到我离开的地方......你可以使用 switch 语句,它会在满足特定条件时执行某些操作;在这种情况下,一旦检测到字符串与您要查找的内容匹配,它就会执行从远程 PC 到本地 PC 的复制项目。见下文:
$computer = (gwmi Win32_ComputerSystem).Manufacturer + " " + (gwmi Win32_ComputerSystem).Model
Switch (Get-ChildItem \\zapp\pc\!Drivers){
"$computer" {Copy-Item -Path $_.FullName -Destination C:\DriverStore }
}
使用 Foreach
循环,我们可以遍历每个文件并尝试使用 if
语句匹配您传递给它的值,在远程 PC 上执行 Copy-Item
找到后放到你的。
Foreach($file in (Get-ChildItem \\zapp\pc\!Drivers)){
if($file -match $computer){ Copy-Item -Path $file.FullName -Destination C:\DriverStore}
}
接下来,我们只是在 Where-Object
运算符的帮助下将文件通过管道传送到 -match
,将指定给它的值与左侧的对象进行匹配。 Foreach-Object
cmdlet(不要与 Foreach
混淆)在末尾使用 -Process
参数来运行输入对象内的每个元素。然后将与您的 PC 匹配的文件夹从远程 PC 复制到您的文件夹中。
$computer = (gwmi Win32_ComputerSystem).Manufacturer + " " + (gwmi Win32_ComputerSystem).Model
Get-ChildItem \\zapp\pc\!Drivers | Where-Object {$_.Name -match $computer} |ForEach-Object -process{ Copy-Item -Path $_.fullname -Destination C:\DriverStore}
希望这是有道理的,可以让您走上正轨。还有一些我没有提到只是为了简单起见,但是@Lee_Daily 确实提到了 .Where()
方法,它也可以在这种情况下使用。
您应该能够在没有数组或任何(显式)过滤的情况下完成此操作。
首先,为了效率,我会像这样初始化 $computer
...
$computerSystem = gwmi Win32_ComputerSystem -Property 'Manufacturer','Model'
$computer = $ComputerSystem.Manufacturer + " " + $computerSystem.Model
如果你想花哨,你也可以做...
$computer = $computerSystem.Manufacturer,$computerSystem.Model -join " "
现在,您无需自己管理和搜索驱动程序目录数组,而可以让文件系统为您执行此操作...
$driverDirectory = Get-Item -LiteralPath "\\zapp\pc\!Drivers\$computer"
如果指定路径不存在对象,这将引发错误。你可以像这样战斗......
$driverDirectory = Get-Item -LiteralPath "\\zapp\pc\!Drivers\$computer" -ErrorAction SilentlyContinue
if ($null -ne $driverDirectory)
{
# $driverDirectory exists; copy drivers
}
...或者像这样...
$driverDirectoryPath = "\\zapp\pc\!Drivers\$computer"
if (Test-Path -Path $driverDirectoryPath)
{
# $driverDirectoryPath exists; copy drivers
}
以这种方式而不是您建议的方式这样做的唯一真正缺点是,如果 !Drivers\
是一个巨大的目录(即数千个子目录)并且您反复查找驱动程序目录,那么该目录枚举可能是明显比自己在数组中缓存结果慢。我猜你的脚本只会复制适用于本地系统的驱动程序,所以,就像我说的,我只是让文件系统做它最擅长的事情。