我有下面的代码根据单个字符串搜索的需要工作 - 现在我试图了解允许用户输入多个字符串的最佳方法,这些字符串会将结果填充到返回电子邮件的数据变量中?对此最好的循环方法是什么:For 循环、ForEach、Do While 或 Do Until?您可以看到我当前设置为搜索单个字符串 MESH (SearchText MESH) 的位置。我应该用 $searchString 替换该单个条目并使用循环方法来填充该变量吗?
我尝试了以下方法 - 但它只产生最后一个值网格。尝试将两个字符串搜索的结果串联到 $data
$strings = @("Alert", "MESH")
foreach ($i in $strings) {
$share = "\\servername\share\folder"
$data=@()
$data = (Get-ChildItem -Path "$share\FIGS\*" -Recurse -Include *.xls, *.xlsx, *.xlsm | Select-Object -Property Directory, Name | ForEach-Object { "{0}\{1}" -f $_.Directory, $_.Name } | Search-Excel -SearchText $i)
}
这是完整的脚本:
# Credits to Boe Prox for his article on https://mcpmag.com/articles/2018/04/06/find-excel-data-with-powershell.aspx
# from which this code is pulled
Function Search-Excel {
[cmdletbinding()]
Param (
[parameter(Mandatory, ValueFromPipeline)]
[ValidateScript({
Try {
If (Test-Path -Path $_) {$True}
Else {Throw "$($_) is not a valid path!"}
}
Catch {
Throw $_
}
})]
[string]$Source,
[parameter(Mandatory)]
[string]$SearchText
#You can specify wildcard characters (*, ?)
)
$Excel = New-Object -ComObject Excel.Application
Try {
$Source = Convert-Path $Source
}
Catch {
Write-Warning "Unable locate full path of $($Source)"
BREAK
}
$Workbook = $Excel.Workbooks.Open($Source)
ForEach ($Worksheet in @($Workbook.Sheets)) {
# Find Method https://msdn.microsoft.com/en-us/vba/excel-vba/articles/range-find-method-excel
$Found = $WorkSheet.Cells.Find($SearchText) #What
If ($Found) {
# Address Method https://msdn.microsoft.com/en-us/vba/excel-vba/articles/range-address-property-excel
$BeginAddress = $Found.Address(0,0,1,1)
#Initial Found Cell
[pscustomobject]@{
WorkSheet = $Worksheet.Name
Column = $Found.Column
Row =$Found.Row
Text = $Found.Text
Address = $BeginAddress
}
Do {
$Found = $WorkSheet.Cells.FindNext($Found)
$Address = $Found.Address(0,0,1,1)
If ($Address -eq $BeginAddress) {
BREAK
}
[pscustomobject]@{
WorkSheet = $Worksheet.Name
Column = $Found.Column
Row =$Found.Row
Text = $Found.Text
Address = $Address
}
#echo $myObject
} Until ($False)
}
Else {
Write-Warning "[$($WorkSheet.Name)] Nothing Found!"
}
}
$workbook.close($false)
[void][System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$excel)
[gc]::Collect()
[gc]::WaitForPendingFinalizers()
Remove-Variable excel -ErrorAction SilentlyContinue
}
$share = "\\servername\share\folder"
$data = (Get-ChildItem -Path "$share\FIGS\*" -Recurse -Include *.xls, *.xlsx, *.xlsm | Select-Object -Property Directory, Name | ForEach-Object { "{0}\{1}" -f $_.Directory, $_.Name } | Search-Excel -SearchText MESH)
$exportObject=@()
ForEach ($row in $data) {
$ExciterObject = New-Object PSObject
$ExciterObject | Add-Member -MemberType NoteProperty -Name "WorkSheet" -Value $row.WorkSheet
$ExciterObject | Add-Member -MemberType NoteProperty -Name "Column" -Value $row.Column
$ExciterObject | Add-Member -MemberType NoteProperty -Name "Row" -Value $row.Row
$ExciterObject | Add-Member -MemberType NoteProperty -Name "Text" -Value $row.Text
$ExciterObject | Add-Member -MemberType NoteProperty -Name "Address" -Value $row.Address
$exportObject += $ExciterObject
}
function ConvertTo-HTMLTable ($obj) {
# Accepts a System.Data.DataTable object or an array of PSObjects and converts to styled HTML table
# add type needed to replace HTML special characters into entities
Add-Type -AssemblyName System.Web
$sb = New-Object -TypeName System.Text.StringBuilder
[void]$sb.AppendLine('<table>')
if ($null -ne $obj) {
if (([object]$obj).GetType().FullName -eq 'System.Data.DataTable'){
# it is a DataTable; convert to array of PSObjects
$obj = $obj | Select-Object * -ExcludeProperty ItemArray, Table, RowError, RowState, HasErrors
}
$headers = $obj[0].PSObject.Properties | Select -ExpandProperty Name
[void]$sb.AppendLine('<thead><tr>')
foreach ($column in $headers) {
[void]$sb.AppendLine(('<th>{0}</th>' -f [System.Web.HttpUtility]::HtmlEncode($column)))
}
[void]$sb.AppendLine('</tr></thead><tbody>')
$row = 0
$obj | ForEach-Object {
# add inline style for zebra color rows
if ($row++ -band 1) {
$tr = '<tr style="background-color: {0};">' -f $oddRowBackColor
}
else {
$tr = '<tr>'
}
[void]$sb.AppendLine($tr)
foreach ($column in $headers) {
[string]$val = $($_.$column)
if ([string]::IsNullOrWhiteSpace($val)) {
$td = '<td> </td>'
}
else {
$td = '<td>{0}</td>' -f [System.Web.HttpUtility]::HtmlEncode($val)
}
[void]$sb.Append($td)
}
[void]$sb.AppendLine('</tr>')
}
[void]$sb.AppendLine('</tbody>')
}
[void]$sb.AppendLine('</table>')
return $sb.ToString()
}
$headerBackColor = '#4F81BD' # backgroundcolor for column headers
$oddRowBackColor = '#DCE6F1' # background color for odd rows
$style = @"
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Report</title>
<meta name="generator" content="PowerShell" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
body {
font-family: Verdana, Arial, Geneva, Helvetica, sans-serif;
font-size: 12px;
color: black;
}
table, td, th {
border-color: black;
border-style: solid;
font-family: Verdana, Arial, Geneva, Helvetica, sans-serif;
font-size: 11px;
}
table {
border-width: 0 0 1px 1px;
border-spacing: 0;
border-collapse: collapse;
}
td, th {
margin: 0;
padding: 4px;
border-width: 1px 1px 0 0;
text-align: left;
}
th {
color: white;
background-color: $headerBackColor;
font-weight: bold;
}
</style>
<p><span style="color: #0000ff;"><strong>Follow below instructions:</strong></span></p>
<ol>
<li>some text (<span style="color: #3366ff;"><strong>some text</strong></span>) some text.</li>
<li>some text “some text” some text.</li>
<li>some text > some text.</li>
<li>some text (some text). some text.</li>
<li>some text “<span style="color: #3366ff;"><strong>some text</strong></span>”.</li>
<li>some text “<span style="color: #3366ff;"><strong>1101 some text</strong></span>”.</li>
<li>some text.</li>
<li>some text– some text “<span style="color: #3366ff;"><strong>some text</strong></span>” – some text.</li>
<li>some text > some text <span style="color: #3366ff;"><strong>some text</strong></span> some text <span style="color: #3366ff;"><strong>Ping</strong></span>. some text“<span style="color: #3366ff;"><strong>Ping successful</strong></span>”.</li>
<li>some text.</li>
<li>some text”.</li>
</ol>
"@
####SET EMAIL VALUES####
$bodyA = '{0}</head><body>{1}</body></html>' -f $style, (ConvertTo-HTMLTable $exportObject)
$EmailTo = "[email protected]"
$EmailFrom = "[email protected]"
$Subject = "My Test"
$Body = $bodyA
$SMTPServer = "mail.domain.org"
####EMAIL PROCESS ####
$anonUsername = "anonymous"
$anonPassword = ConvertTo-SecureString -String "anonymous" -AsPlainText -Force
$anonCredentials = New-Object System.Management.Automation.PSCredential($anonUsername,$anonPassword)
Send-MailMessage -smtpserver "$SMTPServer" -from "$EmailFrom" -to "$EmailTo" -subject "$Subject" -bodyAsHtml "$Body" -credential $anonCredentials
我已经更改了原始函数以接受搜索字符串(或值)数组并循环它们。
另外,我向该函数添加了更多参数,以便您可以指定必须在何处进行搜索 (LookIn)、字符串搜索是否应匹配整个单词或仅匹配其一部分 (LookAt),以及用于指定是否匹配的开关。搜索应区分大小写。
function Search-Excel {
# original code https://mcpmag.com/articles/2018/04/06/find-excel-data-with-powershell.aspx
[cmdletbinding()]
Param (
[parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)]
[ValidateScript({
if (!(Test-Path -Path $_ -PathType Leaf)) {Throw "File does not exist"}
$true
})]
[Alias('FullName')]
[string]$Path,
# Can be a string or any Microsoft Excel data type or an array of search items.
# You can specify wildcard characters (*, ?) if this is a string
[parameter(Mandatory = $true, Position = 1)]
$Find,
[ValidateSet('xlFormulas','xlValues','xlComments','xlCommentsThreaded')]
[string]$LookIn = 'xlValues',
[ValidateSet('xlWhole','xlPart')]
[string]$LookAt = 'xlWhole',
[switch]$CaseSensitive
)
$lookInConstants = @{
xlFormulas = -4123
xlValues = -4163
xlComments = -4144
xlCommentsThreaded = -4184
}
$lookAtConstants = @{
xlWhole = 1 # Match against the whole of the search text.
xlPart = 2 # Match against any part of the search text.
}
$excel = New-Object -ComObject Excel.Application
$workbook = $excel.Workbooks.Open((Convert-Path $Path))
foreach ($worksheet in @($workbook.Sheets)) {
foreach ($searchItem in @($Find)) {
# Find Method https://learn.microsoft.com/nl-nl/office/vba/api/Excel.Range.Find
$found = $worksheet.Cells.Find( $searchItem, # What
[Type]::Missing, # After
$lookInConstants.$LookIn, # LookIn
$lookAtConstants.$LookAt, # LookAt
[Type]::Missing, # SearchOrder
[Type]::Missing, # SearchDirection
$CaseSensitive.IsPresent # MatchCase
)
if ($found) {
# Address property https://learn.microsoft.com/nl-nl/office/vba/api/Excel.Range.Address
$beginAddress = $found.Address(0,0,1,1)
# First Found Cell
[PsCustomObject]@{
WorkSheet = $worksheet.Name
Column = $found.Column
Row = $found.Row
Text = $found.Text
Value = $found.Value2
Address = $beginAddress
}
# Try next finds
while ($true) {
$found = $worksheet.Cells.FindNext($found)
if (!$found -or $found.Address(0,0,1,1) -eq $beginAddress) {
# exit the loop if FindNext returns nothing or the initially found cell again
break
}
[PsCustomObject]@{
WorkSheet = $worksheet.Name
Column = $found.Column
Row = $found.Row
Text = $found.Text
Value = $found.Value2
Address = $found.Address(0,0,1,1)
}
}
}
else {
Write-Warning "[$($worksheet.Name)] Value '$searchItem' not found!"
}
}
}
$workbook.Close($false)
$excel.Quit()
[void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($workbook)
[void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($excel)
[gc]::Collect()
[gc]::WaitForPendingFinalizers()
}
用途:
$strings = 'Alert', 'MESH'
$sourcePath = '\\servername\share\folder\FIGS'
$data = Get-ChildItem -Path $sourcePath -Recurse -Include *.xls, *.xlsx, *.xlsm |
ForEach-Object {
$_ | Search-Excel -Find $strings
}
# output on console
$data | Format-Table -AutoSize
# convert to HTML table
$body = $data | ConvertTo-HTMLTable | Out-String