我已经使用 Windows 搜索工具来查找各种文件是否包含特定文本(在本例中为服务器名称)。
结果列表显示了每个文件。但是,我知道其中一些文件中有多个服务器名称实例。
有没有办法让这个工具列出每次出现的单独行,即使它不会指示每行的位置?
啊,让事情变得更加复杂,我正在搜索一个共享位置(例如 \\netdrive\subfolder\..)
基思的建议看起来不错,但我不确定我是否可以远程将 Powershell 驱动到该位置。
答案1
虽然我没有机会在实际的网络位置进行测试,电源外壳与 UNC 路径配合良好,我测试的引用 UNC 路径的本地文件夹也
\\<ComputerName>\Users\<UserProfileFolder>\Documents
运行良好。因此,只要您有权访问相关文件夹/文件,我认为网络位置不会成为问题。
这应该可以解决问题。详细说明如下:
执行您想要的搜索文件管理器
随着搜索结果窗户保持打开状态,执行以下代码,在
$SearchText
变量赋值中替换您的服务器名称(或其他所需的搜索文本):$SearchText = 'ServerName' ### replace ServerName with the content you're searching for $Shell = New-Object -ComObject shell.application $SearchWindow = @($Shell.Windows()) | ? { $_.Document.Folder.Self.Path -like 'Search Results*' } $FilePaths = @($SearchWindow.Document.Folder.Items()).Path Select-string -Path $FilePaths -Pattern $SearchText | select LineNumber, Path
电源外壳独自一人不知道Shell 命名空间以及虚拟文件夹,例如这台电脑,图书馆, 和T搜索结果。但我们可以创建一个shell.应用程序COM 对象使我们能够弥补这一差距。在电源外壳看起来像这样:
$Shell = New-Object -ComObject shell.application
电源外壳是面向对象的,因此您可以通过管道将其传输到来检查任何对象的属性和方法获取会员(别名为gm
),即$Shell | gm
。这是一种探索和学习的好方法。
这视窗()方法返回另一个 COM 对象,外壳Windows,代表当前打开的文件管理器和IE浏览器windows。使用本机方法枚举这些集合非常棘手,但幸运的是,如果您包装在数组运算符,@($Shell.Winndows())
。然后我们有一个打开的窗口集合。即使打开了多个 Explorer 窗口,假设只有一个带有搜索结果,也很容易通过检查底层文件夹项的路径属性:
$SearchWindow = @($Shell.Windows()) | Where-Object { $_.Document.Folder.Self.Path -like 'Search Results*' }
- 如果你只有一个探索者窗口打开,您可以消除`Where-Object 过滤器 $SearchWindow = @($Shell.Windows())
在该窗口中,我们使用相关的文件夹对象的項目()方法获取文件夹项对应于搜索结果中的文件。因为项目()返回另一个 COM 集合对象,我们使用数组运算符再次:
@($SearchWindow.Document.Folder.Items())
然后使用成员访问运算符(.
)获取路径数组:
@($SearchWindow.Document.Folder.Items()).Path
这应该列出所有文件路径
这选择字符串cmdlet 是一个用于搜索文本文件的强大工具:
Select-String cmdlet 使用正则表达式匹配在输入字符串和文件中搜索文本模式。您可以使用类似于 UNIX 中的 grep 或 Windows 中的 findstr.exe 的 Select-String。
为了您的目的,请使用-Path
参数指定文件路径,并使用-Pattern
参数指定您要查找的文本。找到的每个匹配项的默认返回内容有些冗长:
\\JP\Users\keith\Documents\web\Recipes\Meatloaf -- Uncorrected OCR.txt:22:hour. This
loaf should be basted everj, ts minutes. This is an excelleni;;.tioli
但返回的对象是赛事信息具有以下所有属性的对象:
PS C:\>Select-string -Path (@($SearchWindow.Document.Folder.Items()).Path[1..5]) -Pattern 'x' | gm -MemberType Properties
TypeName: Microsoft.PowerShell.Commands.MatchInfo
Name MemberType Definition
---- ---------- ----------
Context Property Microsoft.PowerShell.Commands.MatchInfoContext Context {get;set;}
Filename Property string Filename {get;}
IgnoreCase Property bool IgnoreCase {get;set;}
Line Property string Line {get;set;}
LineNumber Property int LineNumber {get;set;}
Matches Property System.Text.RegularExpressions.Match[] Matches {get;set;}
Path Property string Path {get;set;}
Pattern Property string Pattern {get;set;}
因此LineNumber
和Path
可能是不错的选择:
Select-string -Path (@($SearchWindow.Document.Folder.Items()).Path) -Pattern 'ServerName' | select LineNumber, Path
因此,有很多解释(授人以鱼不如授人以渔......),但最后相当简洁:
执行您想要的搜索文件管理器
随着搜索结果窗户保持打开状态,执行以下代码,在
$SearchText
变量赋值中替换您的服务器名称(或其他所需的搜索文本):$SearchText = 'ServerName' $SearchText = [Regex]::Escape('ServerName') $Shell = New-Object -ComObject shell.application $SearchWindow = @($Shell.Windows()) | ? { $_.Document.Folder.Self.Path -like 'Search Results*' } $FilePaths = @($SearchWindow.Document.Folder.Items()).Path Select-string -Path $FilePaths -Pattern $SearchText | select LineNumber, Path
上面的代码使用了中间变量以便于理解,但最好让事情在管道中继续进行,并且不要将文字写进代码中。所以这可能更好:
$SearchText = ''ServerName'
$WinCriteria = { $_.Document.Folder.Self.Path -like 'Search Results*' }
$Shell = New-Object -ComObject shell.application
@($Shell.Windows()) | where $WinCriteria | ForEach-Object {
@($_.Document.Folder.Items()).Path | Get-Item | Select-String $SearchText | select LineNumber, Path
}
如果唯一资源管理器窗口打开的是Search Results...
窗口,你可以简化为:
@(@($Shell.Windows()).Document.Folder.Items()).Path | Get-Item | select-string $SearchText |select LineNumber , Path
如果搜索文本包含对正则表达式具有特殊含义的字符,请使用该[Regex]::Escape()
方法:
@(@($Shell.Windows()).Document.Folder.Items()).Path | Get-Item | select-string [Regex]::Escape($SearchText) |select LineNumber , Path
您可能希望按路径分组并显示该路径的所有行号:
@(@($Shell.Windows()).Document.Folder.Items()).Path | Get-Item | select-string [Regex]::Escape($SearchText) |select LineNumber , Path | group Path | select Name , @{ n = 'Line #' ; E = {$_.Group.LineNumber -join ', ' }}