Tail a log file and if match trigger an actrion - powershell

I am currently using the following line of code to return the most recent line of a log via PowerShell
Get-Content -Path C:\folder\thisisalog.log -Tail 1 -Wait |
Where {$_ -match "Remote_http"}
This works correctly and will write to the console each time a log that matches "Remote_http" is logged.
However what I would like to do is run another script when this is returned.
So far I have tried to add to a variable and check if it is null with no luck and I have tried using if statements with no success.
Trying both of these the script runs indefinitely with no output to console or triigers.
I think it may be something to do with -Wait which is causing the issue.

just do it
Get-Content -Path C:\folder\thisisalog.log -Tail 1 -Wait | % {if ($_ -match "Remote_http") {write-host "run code here"}}
or directly into your where
Get-Content -Path C:\folder\thisisalog.log -Tail 1 -Wait | where {if ($_ -match "Remote_http") {write-host "run code here"}}

Related

VisualStudioCode debugger says to supply values and gives prompt

I'm trying to use code to get files in a dir and choose the one(s) that are edited in the last 4 hours. For some reason, when I debug this in VisualStudioCode, the debugger says
Supply values for the following parameters:
Process[0]:
$out_path = "C:\Data\Monitor\PropertiesReport\"
#find latest scan file (within 4 hours from now)
$output_sprdsheet_blob_path = Join-Path -Path $out_path -ChildPath "\OutputSprdsht\" #location of scan output file...looks good for path
Get-ChildItem $output_sprdsheet_blob_path -Filter *.xlsx | Foreach-Object
{
$lastupdatetime=$_.LastWriteTime
$nowtime = get-date
if (($nowtime - $lastupdatetime).totalhours -le 4)
{
Write-Host $_.Name
$excel_File_from = $_.Name
#Select-String -Path $_.Name -Pattern "'Execute Time of Send Thread = 60.'"
}
}
#use file found above next
I'm not sure why powershell gives a prompt to supply values foreach-object, when the path is valid for Get-ChildItem. I've used similar code before, and it worked, but I was using PowershellISE, and the code started with the following instead of the Get-ChildItem.
powershell "Set-Location -Path $log_path ; Get-Item *.* | Foreach {...}
I was having the same issue with the above code, where the visual studio code debugger gave the Process[0] prompt and wanted me to supply values at the foreach. This had been tested and used before as well.
I am trying the Get-ChildItem because of the example below doing this, and it looks like it should work. Any idea why the visual studio code debugger gives the prompt and how to fix it?
I have used write-host to print the dir being used, and I pasted the path printed into windows file explorer and there was a file there, and the path was valid.
My powershell version is 5.1.
example get-childitem
Update:
This prints the filename. I'm not sure why it doesn't give the prompt.
$out_pth = "C:\Data\Monitor\PropertiesReport\"
Set-Location -Path $out_pth
Get-Item *.* | foreach-object {write-host $_.name}
Update2:
This prints the filename too:
Get-ChildItem $out_pth | Foreach-Object {write-host $_.name}
It looks like that newline made the difference. This is working:
Get-ChildItem $out_pth | Foreach-Object {$lastupdatetime=$_.LastWriteTime;$nowtime = get-date; if (($nowtime - $lastupdatetime).totalhours -le 40) {$excel_File_from = $_.Name;write-host $_.name}}
write-host "here"
write-host $excel_File_from
prints:
filename.xlsx
here
filename.xlsx
I changed the time from 4 to 40 hours above, because I realized the file was last edited yesterday. But it found the file as well, without the time check on the file properties.

Unable to use the "ForEach-Object -Parallel" in a directory with a name containing "["

Using the ForEach-Object -Parallel cmdlet in a directory with a name containing "[" will return a WildcardPatternException. Remove -Parallel, it will run successfully.
I created a few directories and ran the following commands.1..5 | ForEach-Object -Parallel {Write-Host $_}A difference of a return for each ran directory is as follows.
PS D:\[example> 1..5 | ForEach-Object -Parallel {Write-Host $_}
WildcardPatternException will be returned.
PS D:\[]example> 1..5 | ForEach-Object -Parallel {Write-Host $_}
PS D:\[ex]ample> 1..5 | ForEach-Object -Parallel {Write-Host $_}
ItemNotFoundException will be returned.
PS D:\[e]xample> 1..5 | ForEach-Object -Parallel {Write-Host $_}
PS D:\]example> 1..5 | ForEach-Object -Parallel {Write-Host $_}
Ran successfully and 5 values are returned.
Is there a way to resolve this without renaming directories?
As mentioned in the comments, this is a bug.
ForEach-Object -Parallel works by offloading execution of the scriptblock to multiple background runspaces via something called a TaskPool.
In order to mimic the callers environment, PowerShell configures the background runspaces to resemble the default runspace, including setting the current provider lotation to whatever the callers is.
Unfortunately, the internal API for setting the current location defaults to expand wildcards, the equivalent of defaulting to:
Set-Location -Path 'D:\[]example'
instead of
Set-Location -LiteralPath 'D:\[]example'
This has now been patched (both for ForEach-Object -Parallel and Start-PSThreadJob), expect both to ship with version 7.1 later this year

How do I output each processing item to file?

Get-AppXPackage -AllUsers | Foreach {Add-AppxPackage -DisableDevelopmentMode -Register "$($_.InstallLocation)\AppXManifest.xml"} | Out-File -path $env:temp\AppXPackage.log
This performs the task that I want it to perform. However, the log file is blank.
I would like for the log file to contain both the errors, and log the individual operations.
I'm not familiar with that particular cmdlet, you could probably try redirecting other output streams (so not stdout) to the log file, and it might work. at the very worst you can do something like this:
Foreach-Object {
try {
Add-AppxPackage ... -ErrorAction Stop
"$_ done" > success.log
} catch {
$_ > errors.log
}
}
The Add-AppxPackagedoesn't return anything, neither does it support -PassThru argument. However, you could push the $_ object to the pipe from the foreach block:
Get-AppXPackage -AllUsers |
Foreach {Add-AppxPackage -DisableDevelopmentMode -Register
"$($_.InstallLocation)\AppXManifest.xml"; $_ } |
Out-File -path $env:temp\AppXPackage.log
As the other 2 answers mentioned, that cmdlet doesn't seem to give any output. Which leaves you with either manual logging or redirection. I just wanted to expand a bit on the other two to give you a couple options.
For redirection, you can do something like this:
.\my_script *>> myfile.log #appen all streams (output and errors) to a file
.\my_script >> output.log 2>> errors.log #send output to one file and error stream to another
For normal logging, take a look at $error, which will contain all the errors in your session. You could start your script with $error.clear(), manually log your output you want since the cmdlet doesn't have output and then end with $error | out-file errors.log

PowerShell to monitor a text file

I have a PowerShell script running on a remote machine. I have it writing data to a text file as it completes its work. Once it's done it writes a specific line.
I have this in the local PowerShell script to monitor that file on the remote machine:
Get-Content -Path $Path -Tail 0 -Wait
It is working great, but how do I tell it to stop monitoring once that specific line is reached?
I tired putting it into a do while loop, but it never releases to complete the do while.
Here is a link to a simpler version of what I am asking:
How to monitor a text file in realtime
The first answer is good, but I don't want to just look for a certain line. I want to write them all VIA Write-Host till that phrase then break from Get-Content and continue with the remaining parts of the script.
Here is what I finally ended up with. It is not pretty due to the way I exited the ForEach-Object.
Get-Content -Path $path -Tail 0 -wait | ForEach-Object{if($_ -match $word){write-host "- $_" ;cjklnsrvf } else {write-host "- $_"} }
I used a Try and Catch for the cjklnsrvf in the if statement above. This is done because ForEach-Object cannot use the break or continue statements. It seems that when piping a ForEach loop it is turned into (alias) the ForEach-Object cmdlet. The ForEach-Object cmdlet doesn't use the break and continue commands like a foreach loop.
If you use a break in a ForEach-Object it will immediately exit the whole script. There was one guy on one site that brought up loop death by garbage, and it indeed does work here as well.
UPDATE: Here is what I finally ended up with. It is not pretty due to the way I exited the foreach-object.
Get-Content -Path $path -Tail 0 -wait | ForEach-Object{if($_ -match $word){write-host "- $_" ;cjklnsrvf } else {write-host "- $_"} }
I used a Try and Catch for the cjklnsrvf in the if statement above. This is done because ForEach-Object cannot use the break or continue statements. It seems that when piping a ForEach loop it is turned into(alias) the ForEach-Object cmdlet. The ForEach-Object cmdlet doesn't use the break and continue commands like a foreach loop. If you use a break in a ForEach-Object it will immediately exit the whole script. There was one guy on one site that brought up loop death by garbage and it indeed does work here as well.
Get-Content $path -Tail 0 -Wait | foreach { if ($_ -eq "Specific Line") { Write-Output $_ ; break } }
Or just the break, obviously, if you have no use of the output.
Do {
$content = get-content $path -tail 0 -ea 00 | where {$_ -like "*string found*"}
Sleep -milliseconds 1000
} until($content)
Invoke-Command -ComputerName xxx -Credential $cred -ScriptBlock {if(test-path 'c:\1.txt'){cat 'c:\1.txt'}else{'file not exist'}}

powershell append to output

I'm 'teaching myself to powershell' and have come a cropper already, and google/this site hasn't enabled me to find a solution. I'm compiling a text file with filelists from different directories, but i'm having trouble appemnding new data to the file.
get-childitem $dir -recurse | % {write-output $_.fullname} >$file
creates my file, but then i want to APPEND new records from the below
get-childitem $dir2 -recurse | % {write-output $_.fullname} >$file
I've tried both add-content and -append, but I cant figure out what I'm not doing to get it right.
Try:
get-childitem $dir -recurse | % {write-output $_.fullname} >> $file
(Tested and works)
The double >> makes it append always, a single > overwrites each time.
Or change your syntax to use Out-File
get-childitem $dir -recurse | % {write-output $_.fullname} | out-file -filepath $file -Append
(untested)
In this case the variable $file must hold the full path. Like: C:\directory\filename.txt
You can use Out-File to write to a file, adding the append parameter will append to the file.
Get-ChildItem $dir -recurse | Select-object -ExpandProperty Fullname | Out-File -FilePath $file
Get-ChildItem $dir2 -recurse | Select-object -ExpandProperty Fullname | Out-File -FilePath $file -Append
Short Answer
The pipeline used here can be eliminated, and usage of Out-File would make life easy:
Out-File (Get-ChildItem $dir -Recurse).FullName -FilePath $File
To append would be to simply use the -Append flag:
Out-File (Get-ChildItem $dir2 -Recurse).FullName -FilePath $File -Append
Note: This only works in PowerShell v3 and up, as PowerShell v2 relied on the pipeline to expand properties of objects within an array. In that case, the best route is to use something more like #david-martin proposed on this same thread.
Long Answer, and Best Practices
In a different thread, Script to Append The File, they were having similar difficulties with appending files. Though, they were also using the pipeline in a way that was unnecessary (more so than you have used in your example).
Their pipeline usage looked like this:
$PathArray | % {$_} | Out-File "C:\SearchString\Output.txt"
Now, again, Out-File has an -Append parameter. Simply modifying their code to have it tagged on at the end took care of things.
Though, their ForEach-Object statement (the % symbol) is pretty useless in the pipeline and isn't needed (very close in similarity to how yours is used). This is because you are only using the ForEach-Object loop to output the object without any modification. This is exactly what the pipeline does by default, which is pass each object along to the next command.
For more information on the pipeline: About Pipelines
If Update-Help has been run locally, one can use Get-Help to locally run Get-Help about_pipelines to see information too.
Instead of this:
$PathArray | % {$_} | Out-File "C:\SearchString\Output.txt" -Append
We could do this:
$PathArray | Out-File "C:\SearchString\Output.txt" -Append
[Recommended] That example can also eliminate the need for the pipeline all together, as using a pipeline is less efficient if it can be done without it. Doing everything one can possibly do without the pipeline, or to the left of each pipe in the pipeline, is to "filter left" (see the following article for more about why one should filter left, format right: Filtering Command Output in PowerShell):
Out-File -InputObject $PathArray -FilePath "C:\SearchString\Output.txt" -Append
Note: In the case above, -Append is only needed if the file already exists and is being extended.
Remember: Get-Help, and Read The Friendly Manual (RTFM)
The easiest way to troubleshoot is to checkout help documentation. Use Get-Help to checkup whatever you need: parameter sets, available parameters, examples, etc. Make sure to run Update-Help in order to have detailed documentation available locally. To checkout everything:
Update-Help
Get-Help Out-File -Full
For more detailed information that is good to know about data stream/output redirection:
PowerShell redirection operators, such as > and >> (but also redirection of data streams with n> and n>&1), and the available streams per PowerShell version: About Redirection in PowerShell (or: Get-Help about_redirection in PowerShell)
Tee-Object cmdlet), a cmdlet that acts as a more robust version of Out-File (or: Get-Help tee-object in powerShell)