2
votes

The txt file is just a bunch of UNC paths, i am trying to get a list of UNC paths from this text file put into another text file after the test-path is validated. it shows the validated paths on screen but the text file does not populate.

$cfgs = Get-Content .\cfgpath.txt
$cfgs | % {
  if (Test-Path $_) { write-host "$_" | Out-File -FilePath c:\temp\1.txt -Append }
}
2

2 Answers

3
votes

To complement Zam's helpful answer with background information:

  • Write-Host writes to the host[1] (typically, the console aka terminal), which bypasses PowerShell's success output stream and therefore sends nothing trough the pipeline.

    • See the bottom section of this answer for when Write-Host is appropriate; in short: you should generally only use it for display-only output.
  • Write-Output is the appropriate cmdlet for producing data output, but it is rarely necessary, because you can rely on PowerShell's convenient implicit output behavior, as shown in Steven's answer and explained in this answer.


Also, your command will perform much better if you simply pipe the % (ForEach-Object) command's output as a whole to a single Out-File call, rather than calling Out-File -Append for each input path.

Instead of using % with conditional explicit output, you can more elegantly implement your command with the Where-Object cmdlet:

Get-Content .\cfgpath.txt |
  Where-Object { Test-Path $_ } |
    Out-File -FilePath c:\temp\1.txt

Also note that for saving strings to a file it is more efficient to use Set-Content instead of
Out-File, though note that in Windows PowerShell the default output character encoding differs (no longer a concern in PowerShell [Core] 6+, which consistently defaults to BOM-less UTF-8); see this answer for when to choose which cmdlet.

By contrast, Out-File and > (its effective alias) use PowerShell's formatting system to write for-display representations of any non-string input objects to the output file, the same way that output renders to the display by default.
In other words: To save objects to a file in a way that is suitable for later programmatic processing, you need to use a structured file format, such as CSV (Export-Csv) or JSON (ConvertTo-Json, combined with Set-Content).


[1] In PowerShell 5.0 and higher, Write-Host now writes to a new stream, the information stream (number 6), which by default prints to the host. See about_Redirection. Therefore, a 6> redirection now technically does allow you to send Write-Host output through the pipeline (though doing so is not a good idea) or capture / redirect it; e.g.,
Write-Host hi 6>&1 | % { "[$_]" }. Note that the type of the objects output by this redirection is System.Management.Automation.InformationRecord.

2
votes

Write-Host only writes to the console. I believe what you want there is Write-Output.

$cfgs = Get-Content .\cfgpath.txt
$cfgs | % {
  if (Test-Path $_) { write-output "$_" | Out-File -FilePath c:\temp\1.txt -Append }
}

Additionally you can just omit the Write-Output and that works too.

$cfgs = Get-Content .\cfgpath.txt
$cfgs | % {
  if (Test-Path $_) { "$_" | Out-File -FilePath c:\temp\1.txt -Append }
}