Piping to More Than One Location - PowerScript - powershell

I want to do something like this-
"Error array cleared." | Out-File $ErrorLog $InfoLog -Append
However it's not working. Is this possible without writing another line to output it to the other file?

You can also use Tee-Object to accomplish the same thing. Look at example 3 on that page. Here is a quick sample that grabs the contents of the current directory and saves it to two files.
Get-ChildItem | Tee-Object -FilePath teetest.txt | Out-File teetest2.txt

One way is with a short function like this:
function Out-FileMulti {
param(
[String[]] $filePath
)
process {
$text = $_
$filePath | foreach-object {
$text | out-file $_ -append
}
}
}
Example:
"Out-FileMultiTest" | Out-FileMulti "test1.log","test2.log"
(Writes the string "Out-FileMultiTest" to both test1.log and test2.log)

Found this snippet of code which does what I need-
"Test" | %{write-host $; out-file -filepath $ErrorLog -inputobject $ -append}

Related

Out-File only if the variable doesn't exist in the file

Goal: Write a variable to a text file ONLY if it doesn't already exist in that text file.
What I'm doing:
if (! (Get-Content "C:\historique.txt" | Where-Object {$_ -like $var})) {
$var | Out-File -Encoding Ascii -FilePath "C:\historique.txt" -Append -Force
}
"If the $var is NOT found in the file, Out-File..."
It works, but is this the best / fastest approach? The file won't get really huge but I want it to be as optimal as possible.
You can use the -notmatch regex comparison to see if the file content does not have the wanted string in $var, like so:
$file = 'C:\historique.txt'
$var = 'blah'
if ((Get-Content -Path $file -Raw) -notmatch [regex]::Escape($var)) {
Add-Content -Path $file -Value $var -Encoding Ascii -Force
}

Powershell: Querying multiple strings and outputting to both user and file

I've been given the duty of validating installation of an update across many hosts. This validation is performed by querying for a string of an error code that signifies success. I would like this output to both appear in the shell and also be written to a file.
$computerList = #($userInput)
foreach ($_ in $computerList){
get-content -tail 20 ("filepath") `
| where {$_| select-string "All steps complete!"} `
| where {$_| select-string "Output Error = 0 "} `
| out-file C:\users\me\Desktop\validation_log.txt -append
}
I based the multiple string "grep"-ing off of an online article,
However, this doesn't write the desired strings to the out-file path, nor does it display in console.
Can anyone please explain the best method for querying multiple strings and then outputting those to a file?
Your example is more complex than necessary.
You could just chain the Select-String. And Tee-Object is the way to go if you want to output something to both file and down the pipeline:
PS C:\temp> Get-Content -LiteralPath ".\input.txt"
All steps complete!
All steps complete! Output Error = 0
asdf
PS C:\temp> Get-Content -LiteralPath ".\input.txt" | Select-String -Pattern "All steps" | Select-String -Pattern "Output Error" | ForEach-Object {$_.ToString()} | Tee-Object -FilePath ".\output.txt" -Append
All steps complete! Output Error = 0
PS C:\temp> Get-Content -LiteralPath ".\output.txt"
All steps complete! Output Error = 0
The above behaves like an logical "and" for each pattern. If you want to "or" the patterns you could use the fact that the pattern is a regular expression:
PS C:\temp> Get-Content -LiteralPath ".\input.txt" | Select-String -Pattern "All steps|Output Error" | ForEach-Object {$_.ToString()} | Tee-Object -FilePath ".\output.txt" -Append
All steps complete!
All steps complete! Output Error = 0
Also notice that Select-String outputs Microsoft.PowerShell.Commands.MatchInfo objects and not strings. You will probably get unwanted newlines in your output if you pipe these directly to Tee-Object. I therefore convert these to strings in the Foreach-Object

Out-File inside a foreach statement

im trying to run this script, it works but every time that it changes from item on the list it erases the file and starts over.
what i need this to do is to get from the list of items all the users and put them all in a single text file.
$sitios = Get-Content -Path C:\sitios.txt
Connect-SPOService -Url https://aaa.sharepoint.com/ -Credential Admin#aaa.onmicrosoft.com
foreach ($sitio in $sitios){
$sitio
Get-SPOUser -Site $sitio -Limit ALL | Out-File -FilePath C:\usuarios.txt
}
any help is appreciated
You could use the -Append switch of Out-File but all you should have to do is move it outside the loop.
(foreach ($sitio in $sitios){
Write-Host $sitio
Get-SPOUser -Site $sitio -Limit ALL
}) | Out-File -FilePath C:\usuarios.txt
That way all output will be sent to Out-File. I added Write-Host $sitio so that was not going to be in the file. You could also use Set-Content which is considered the preferential choice over Out-File
The brackets are needed around the loop so that we can use the pipe output. That foreach construct cannot have data directly piped from it. An answer here covers the reason.
That all being said you could then do something like this
$sitios | ForEach-Object{
Write-Host $_
Get-SPOUser -Site $_ -Limit ALL
} | Set-Content C:\usuarios.txt
This output should be a complex object that might not have a proper tostring equivalent. You can still get all the data with something like this instead.
$sitios | ForEach-Object{
Write-Host $_
Get-SPOUser -Site $_ -Limit ALL
} | Export-CSV C:\usuarios.txt -NoTypeInformation
You can use the Add-Content Cmdlet:
https://technet.microsoft.com/en-us/library/ee156791.aspx
Instead of Out-File use Add-Content
as in:
[...] | Add-Content C:\usuarios.txt

Powershell: Start-Transcript to just log the commands and not results

Is it possible to make start-transcript log just the commands and not the results?
No, this is not possible now. Here is the suggestion for the version next: add Start-Transcript filters
This was a powershell.com tip of the day recently:
When you run Start-Transcript, PowerShell will document all console input and output in a file. To remove all output and create a file with your PowerShell commands only, you should use this piece of code:
$path = "$home\Documents\allcommands.txt"
dir $home\Documents\*transc* |
ForEach-Object { Get-Content $_.FullName } |
ForEach-Object { if ($_ -match '^PS.*?>') {
$_.SubString($matches[0].Length).Trim()
}
} |
Where-Object { $_ } |
Out-File $path
Invoke-Item $path

How do I add a newline to command output in PowerShell?

I run the following code using PowerShell to get a list of add/remove programs from the registry:
Get-ChildItem -path hklm:\software\microsoft\windows\currentversion\uninstall `
| ForEach-Object -Process { Write-Output $_.GetValue("DisplayName") } `
| Out-File addrem.txt
I want the list to be separated by newlines per each program. I've tried:
Get-ChildItem -path hklm:\software\microsoft\windows\currentversion\uninstall `
| ForEach-Object -Process { Write-Output $_.GetValue("DisplayName") `n } `
| out-file test.txt
Get-ChildItem -path hklm:\software\microsoft\windows\currentversion\uninstall `
| ForEach-Object {$_.GetValue("DisplayName") } `
| Write-Host -Separator `n
Get-ChildItem -path hklm:\software\microsoft\windows\currentversion\uninstall `
| ForEach-Object -Process { $_.GetValue("DisplayName") } `
| foreach($_) { echo $_ `n }
But all result in weird formatting when output to the console, and with three square characters after each line when output to a file. I tried Format-List, Format-Table, and Format-Wide with no luck. Originally, I thought something like this would work:
Get-ChildItem -path hklm:\software\microsoft\windows\currentversion\uninstall `
| ForEach-Object -Process { "$_.GetValue("DisplayName") `n" }
But that just gave me an error.
Or, just set the output field separator (OFS) to double newlines, and then make sure you get a string when you send it to file:
$OFS = "`r`n`r`n"
"$( gci -path hklm:\software\microsoft\windows\currentversion\uninstall |
ForEach-Object -Process { write-output $_.GetValue('DisplayName') } )" |
out-file addrem.txt
Beware to use the ` and not the '. On my keyboard (US-English Qwerty layout) it's located left of the 1.
(Moved here from the comments - Thanks Koen Zomers)
Give this a try:
PS> $nl = [Environment]::NewLine
PS> gci hklm:\software\microsoft\windows\currentversion\uninstall |
ForEach { $_.GetValue("DisplayName") } | Where {$_} | Sort |
Foreach {"$_$nl"} | Out-File addrem.txt -Enc ascii
It yields the following text in my addrem.txt file:
Adobe AIR
Adobe Flash Player 10 ActiveX
...
Note: on my system, GetValue("DisplayName") returns null for some entries, so I filter those out. BTW, you were close with this:
ForEach-Object -Process { "$_.GetValue("DisplayName") `n" }
Except that within a string, if you need to access a property of a variable, that is, "evaluate an expression", then you need to use subexpression syntax like so:
Foreach-Object -Process { "$($_.GetValue('DisplayName'))`r`n" }
Essentially within a double quoted string PowerShell will expand variables like $_, but it won't evaluate expressions unless you put the expression within a subexpression using this syntax:
$(`<Multiple statements can go in here`>).
I think you had the correct idea with your last example. You only got an error because you were trying to put quotes inside an already quoted string. This will fix it:
gci -path hklm:\software\microsoft\windows\currentversion\uninstall | ForEach-Object -Process { write-output ($_.GetValue("DisplayName") + "`n") }
Edit: Keith's $() operator actually creates a better syntax (I always forget about this one). You can also escape quotes inside quotes as so:
gci -path hklm:\software\microsoft\windows\currentversion\uninstall | ForEach-Object -Process { write-output "$($_.GetValue(`"DisplayName`"))`n" }
Ultimately, what you're trying to do with the EXTRA blank lines between each one is a little confusing :)
I think what you really want to do is use Get-ItemProperty. You'll get errors when values are missing, but you can suppress them with -ErrorAction 0 or just leave them as reminders. Because the Registry provider returns extra properties, you'll want to stick in a Select-Object that uses the same properties as the Get-Properties.
Then if you want each property on a line with a blank line between, use Format-List (otherwise, use Format-Table to get one per line).
gci -path hklm:\software\microsoft\windows\currentversion\uninstall |
gp -Name DisplayName, InstallDate |
select DisplayName, InstallDate |
fl | out-file addrem.txt
The option that I tend to use, mostly because it's simple and I don't have to think, is using Write-Output as below. Write-Output will put an EOL marker in the string for you and you can simply output the finished string.
Write-Output $stringThatNeedsEOLMarker | Out-File -FilePath PathToFile -Append
Alternatively, you could also just build the entire string using Write-Output and then push the finished string into Out-File.