我正在搜索以下站点中所有Windows服务器的C和E驱动器 包含putty.exe及其版本的任何现有副本的Active Directory。 输出需要具有服务器名称,可执行文件的完整路径, 和文件版本。到目前为止,我有以下代码(目前仅在使用 两台服务器进行测试:
$ComputerName = Get-ADComputer -filter "name -like 'computer01' -or name `
-like 'server01'" | select -ExpandProperty name
$OutputArr = @()
$findFiles = foreach($computer in $computername){
$file = Invoke-Command -computername $computer { Get-ChildItem -Path `
c:\, e:\ -Recurse | where-object{(!$_.psiscontainer -eq $true) -and `
($_.name -like "putty.exe")} | ForEach-Object -process {$_.fullname} }
$output = $OutputObj = New-Object -TypeName PSobject
$OutputObj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $computer
$OutputObj | Add-Member -MemberType NoteProperty -Name FilePath -Value $file
$OutputArr += $OutputObj
Write-Verbose $OutputObj
}
$OutputArr | fl
上面的代码输出以下数组:
ComputerName : COMPUTER01
FilePath : {C:\Program Files\PuTTY\putty.exe, C:\Program Files (x86)\PuTTY\PUTTY.EXE}
ComputerName : SERVER01
FilePath : {C:\Program Files (x86)\putty\putty.exe, C:\Users\testuser\Desktop\Public Desktop\putty.exe}
这将产生正确的数据,但是现在我需要针对每个运行另一个代码段 计算机名下的单独文件路径,但是不确定如何完成此操作 带有多个条目的完整文件路径。
基本上,我需要将数组中的每个ComputerName分成多行:
COMPUTER01,C:\Program Files\PuTTY\putty.exe
COMPUTER01,C:\Program Files (x86)\PuTTY\PUTTY.EXE
SERVER01,C:\Program Files (x86)\putty\putty.exe
等等...
数组不是正确的方法吗?
答案 0 :(得分:0)
我不确定您到底想做什么,但这应该可以遍历您的自定义对象。您的Invoke-Command也可以简化。
$file = Invoke-Command -computername $computer { Get-ChildItem -Path "C:\", "E:\" -Recurse -File -Filter "putty.exe" | Select -Property VersionInfo }
$OutputObj = New-Object -TypeName PSobject
$OutputObj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $env:COMPUTERNAME
$OutputObj | Add-Member -MemberType NoteProperty -Name FilePath -Value $file
$OutputArr += $OutputObj
foreach ($item in $OutputArr)
{
for ($i = 0; $i -lt $item.FilePath.Count; $i++)
{
Write-Output ([string]::Join(', ', $item.ComputerName, $item.FilePath[$i].VersionInfo.FileName, $item.FilePath[$i].VersionInfo.FileVersion))
}
}
答案 1 :(得分:0)
进行远程会话时,PowerShell可能会变得棘手。以下脚本对您来说应该是一个很好的起点。以下是一些其他需要改进的地方:
Get-ChildItem -Recurse
会占用过多的内存,并且由于100%的内存使用,您可能会导致意外的页面文件扩展,甚至使服务器无响应。在下面的代码段中,我使用了一系列众所周知的路径。如果您需要确定是否在其他计算机上启动了putty.exe,则您的监视解决方案有望获得过程性能数据,您可以在其中搜索putty.exe。winrm get winrm/config/winrs
,则会看到上限。 $computerNames = @('computer1','computer2')
foreach($computer in $computerNames)
{
<#
First Script Block checks well known paths for putty.exe
#>
$puttyResults = Invoke-Command -ComputerName $computer -ScriptBlock {
$wellKnownPaths = @()
$wellKnownPaths += Join-Path $env:USERPROFILE -ChildPath "Desktop"
$wellKnownPaths += "D:\tools\"
$wellKnownPaths += $env:Path.Split(';')
$puttyPaths = @()
foreach($path in $wellKnownPaths)
{
$puttyPaths += Get-ChildItem $path -Filter "putty.exe" -Recurse
}
if($puttyPaths.Count -gt 0)
{
$resultsArray = @()
foreach($path in $puttyPaths)
{
$resultsArray += [PSCustomObject]@{
ComputerName = $env:COMPUTERNAME
PuttyPath = $path.FullName
}
}
return $resultsArray
}
return $null
}
if($puttyResults -ne $null)
{
foreach($result in $puttyResults)
{
<#
Second script block takes action against putty.exe
#>
$puttyExists = Invoke-Command -ComputerName $computer -ArgumentList @($result.PuttyPath) -ScriptBlock {
Param(
$PuttyPath
)
return (Test-Path $PuttyPath)
}
if($puttyExists)
{
$msg = "Putty exists on '{0}', at '{1}'" -f $result.ComputerName, $result.PuttyPath
Write-Host $msg -ForegroundColor:Yellow
}
}
}
}
答案 2 :(得分:0)
如果严格使用$OutputArr
中已存储的内容,则可以进行以下操作:
$out = foreach ($line in $OutputArr) {
if ($line.filepath.count -gt 1) {
foreach ($fp in $line.FilePath) {
[pscustomobject][ordered]@{ComputerName = $line.ComputerName; FilePath = $fp}
}
}
else {
$line
}
}
$out | ConvertTo-Csv -NoTypeInformation
foreach循环使用属性ComputerName和FilePath创建新对象,并将它们作为对象数组存储在$out
中。
如果您不关心属性,而只希望使用逗号分隔的列表,则可以使用以下内容:
foreach ($line in $OutputArr) {
if ($line.filepath.count -gt 1) {
foreach ($fp in $line.FilePath) {
"{0},{1}" -f $line.ComputerName,$fp
}
}
else {
"{0},{1}" -f $line.ComputerName,$line.FilePath
}
}
这与第一个解决方案执行相同的循环,但是使用格式运算符(-f
)格式化输出。传递到ConvertTo-Csv
时,会将输出格式为逗号分隔,并带有标题属性。
您甚至可以在将任何内容存储在$OutputArr
中之前将所需的功能移入代码中。我觉得在创建$OutputArr
的所有其他循环之后进行所有这些操作只会增加效率低下。