Power Shell Get-ChildItem 然后通过管道传输到 Get-Content

Power Shell Get-ChildItem then pipe to Get-Content

我正在尝试检索已知文件名的未知文件路径,然后对该文件名执行 Get-Content 以便我可以对其进行修改。我知道该文件将在 C:\Users$env:UserName\ 中,但就我所能及的范围而言(最终用户可能会将其放在更远的地方,例如文档或桌面或其他地方)。

它似乎可以执行 Get-ChildItemGet-Content,但由于某些原因我不能在同一个脚本中同时执行这两项操作。

总体目标:将 Get-ChildItem 的结果通过管道传递给 Get-Contents 函数,以便我可以修改文件。

这是我的代码:

(Get-ChildItem -Path C:\Users$env:UserName -Filter QA11test.hep) | 
    Foreach-Object {
        $_ # send the current line to output
        if($_ -match "SSL/TLS User Cipher Suites=DEFAULT"){
            "IP Port=2023"
            "Security Option=2"
            $Message = "Your host explorer session has been updated."
            Msg $env:UserName $Message
            exit
        } else {
            $Message = "Script Failed."
            Msg $env:UserName $Message
            exit
        }
    } | Set-Content C:\Users$env:UserName\Telnet\QA11TestSecure.hep

需要帮助!谢谢!

对于如何获取文件及其内容,然后检查文件内容中的任意行,似乎存在一些困惑。我建议不要将其写在大型复合命令中,而是将其分解为不同的样式,以便最大程度地减少管道混乱。有多种方法可以完成相同的任务,有些方法比其他方法更容易遵循,尤其是在调试时。

$fileoutput = @'
IP Port=2023
Security Option=2
'@
$FileToLookAt = Get-ChildItem -Path C:\Users$env:UserName -Recurse -Filter "QA11test.hep" | Get-Content
if ($FileToLookAt)
{
    $found = ""
    $found = $FileToLookAt | Where-Object {$_ -eq 'SSL/TLS User Cipher Suites=DEFAULT'}
    if ($found)
    {
        $Message = "Your host explorer session has been updated."
        Set-Content -Path C:\Users$env:UserName\Telnet\QA11TestSecure.hep -Value $fileoutput -Force
    } else 
    {
        $Message = "Script Failed."
    }
} else 
{
    $Message = "QA11test.hep not found."
}
Msg $env:UserName $Message

编辑:好的,确实应该检查 Set-Content 以确保 file/path 存在。假设是这样,这样的事情应该可行。

在最简单的情况下,您需要做的就是使用 Get-Content 命令插入一个管道段:

Get-ChildItem -Path C:\Users$env:UserName -Filter QA11test.hep |
  Get-Content | # Send the lines of the input file(s) one by one to ForEach-Object
    ForEach-Object { ...

但是,您的方法存在问题

  • 如果找到文件,则无条件写入输出文件 - 即使未对输入内容进行任何修改。

    • 此外,由于代码中的 exit 语句,任何剩余的输入行都从输出文件中省略
  • 如果找到 no 文件,输出文件要么被创建为一个空文件(0 字节),要么,如果它已经存在, 替换为一个空文件。


相反,我建议使用 一种基于 switch statement 的方法,它更快、更简洁、更灵活:

值得注意的是,此解决方案仅在找到输入文件时创建/替换输出文件并且对其进行了修改。

Get-ChildItem -Path C:\Users$env:UserName -Filter QA11test.hep | ForEach-Object {
  $updated = $false
  $newLines = switch -File $_.FullName -Regex { # Loop over all file lines
    'SSL/TLS User Cipher Suites=DEFAULT' { 
       $_, "IP Port=2023", "Security Option=2" # send 2 additional lines
       $updated = $true
    }
    default { $_ } # pass other lines through
  }
  # Rewrite the file only if modifications were made.
  if ($updated) { $newLines | Set-Content C:\Users$env:UserName\Telnet\QA11TestSecure.hep }
  # Emit the appropriate status message.
  Msg $env:UserName ('Nothing to update.', 'Your host explorer session has been updated.')[$updated]
}

注意:如果您还需要知道是否找到了输入文件 - 无论是否需要更新 - 设置 $found = $true在脚本块内并在命令后检查它:if (-not $found) { Msg $env:UserName 'QA11test.hep not found' }

  • switch -File $_.FullName -Regex 逐行读取输入文件,并根据正则表达式条件匹配每一行:

    • 如果正则表达式匹配,则输出原始行 ($_),以及 2 条附加行;另外,设置标志 $updated 以指示内容已修改。
    • 所有其他行(default 条件行)按原样输出。
  • $newLines = ... 捕获数组中的(可能修改的)行。

    • 请注意,这意味着所有行都一次存储在内存中,但文本文件通常不是问题。
  • 只有设置了$updated才会写入输出文件(Set-Content)。

  • 最后,Msg 命令被调用并带有状态适当的消息。

    • 注意 ('msg1', 'msg2')[$updated] 表达式,它是根据标志选择两个值之一的快捷方式:如果 $updated$true,则 $true 被强制为数组索引 1,因此选择 'msg2';如果是$false,索引是0,选择'msg1'

谢谢大家的帮助!

(@mklement0,我将修改它以做一些接近你最后一个 post 所做的事情!这对我很有帮助。)

我从不同的 post 中提取了点点滴滴,这就是我想出的,它可以满足我的需要。

此 PowerShell 脚本获取已知文件的完整路径,"QA11test.hep" 并将其加载到一个变量中供以后使用。然后它会在该文件的内容中搜索特定字符串 "SSL/TLS..etc",如果找到它,它会在找到的行下方添加两行,"Port=2023" 和 "Security Option 2"。然后它获取该新文件并将其添加到 C:\Users\$env:UserName\Desktop\QA11TestSecure.hep 而不更改原始 QA11test.hep 文件。因此,它不是从 get-childitem 到 get-content 的管道,而是将从 get-childitem 函数检索到的项目放入一个变量中,然后 get-content 函数可以搜索该变量。效果很好!

$FileToLookAt = (Get-ChildItem -Path C:\Users$env:UserName\ -Recurse -Filter "QA11test.hep") | % { $_.FullName }
$User = $env:UserName
if ($FileToLookAt){
    $updated = $false
    $addtls = Get-Content ($FileToLookAt) | Foreach-Object {
        $_ # send the current line to output
        if($_ -match "SSL/TLS User Cipher Suites=DEFAULT"){
            "IP Port=2023"
            "Security Option=2"
            $updated = $true
        }
    }
    if ($updated) {
        $addtls | Set-Content -Path C:\Users$env:UserName\Desktop\QA11TestSecure.hep
        $Message = "Host Explorer updated.`nPlease ensure there is a gold LOCK icon at the bottom left `nof the host explorer window.`nIf not, please contact the help center. Thank you."
    } else {
        $message = "File was not updated.`nPlease contant the help center immediatly."
    }
} else {
    $Message = "QA11test.hep not found.`nPlease contact the helpdesk immediately."
}
Msg $env:UserName $Message
exit