I have a lot of log files that I wish to extract the distinct error message from for a specific trace writer.
The log files are SharePoint ULS logs.
The headings are:
Timestamp
Process
TID
Area
Category
EventID
Level
Message
Correlation
So given a specific process name I want all distinct Messages.
If I was to use SQL I would write something like this:
select Distinct Message from where Process like 'myprocessname'
I'd like to do this with powershell across a whole set of log files.
I believe the ULS log is tab or space delimited.
You might be interested in Microsoft's Log Parser which essentially lets you run SQL like statements across a set of log files. You can also use this with Powershell. Here are some links:
Analyze Web Stats with Log Parser
Integrating Microsoft Log Parser in Windows Powershell
Logparser and Powershell
Assuming the log file isn't too huge, you can read the contents in using Import-Csv like so:
$data = Import-Csv .\log.csv -Delimiter "`t"
I'm assuming the delimiter is tab since it is likely any message will contain spaces. Once you have the log data you can use the standard PowerShell query operators like so:
$data | Where {$_.Process -eq 'processname.exe'} | Select Message -Unique
If the log file is huge (such that Import-Csv eats up too much memory) then I would either try using Log Parser or use a regex and parse the log, one line at a time.
Related
I'm new to Powershell (of course), and having troubles with a seemingly simple process. I have found a couple of examples that I think I am following, but they aren't working for me.
What I am trying to do: add a bunch of users to the local Windows OS, by reading from a CSV file (has names, usernames, passwords, etc).
My understanding is that the 'Import-CSV' cmdlet is supposed to return an object-like thing you can iterate over:
"The result of an Import-Csv command is a collection of strings that
form a table-like custom object."
When I perform that step, saving it to a variable, it seems that there is only ever 1 row present. And if I don't provide the "-Header" parameter, I get errors about a 'member is already present'... even if I include the header in the CSV file (my original file did not include a header row in the CSV file.)
I have tried various methods trying to get a Count of the imported CSV results, just trying to see what the data is, but I'm not having any luck. (MS Docs say you can use the Count property.)
MS Docs (https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/import-csv?view=powershell-7.2) say this about "Import-CSV":
Outputs
Object
This cmdlet returns the objects described by the content in the CSV
file.
...
Notes
Because the imported objects are CSV versions of the object type...
The result of an Import-Csv command is a collection of strings that
form a table-like custom object. Each row is a separate string, so you
can use the Count property of the object to count the table rows. The
columns are the properties of the object and items in the rows are the
property values.
An example of my input CSV file:
"ISA","LOG","Consulting & Other","Vendor","Isalog","alsdkjfalsdjflasdkfjalsdkfjlaksdjflkasdfj"
"Bry","Link","Bry Link","Vendor","Bry","asdkfjalsdjflaksdjflasdkjflaksdfj"
"Michael","Had","Premier Service Of Western","Vendor","Michael","alsdkfjalskdjflaksdjflaksdfjalksdfj"
Code of one example that I am testing:
param ($InputFile)
Write-Host "Provided input file: $InputFile"
$CSV = Import-CSV -Path $InputFile -Header 'FirstName', 'LastName', 'FirmName', 'Type', 'Username', 'Password'
foreach($LINE in $CSV)
{
$NewUser="$($LINE.USERNAME)"
$NewPass="$($LINE.PASSWORD)"
$SecurePass=ConvertTo-SecureString –AsPlainText -Force -String "$NewPass"
Write-Host "User = $NewUser"
#New-LocalUser -Name $NewUser -Password $SecurePass
}
And a screenshot of my script plus the run results:
Running on: Windows server 2019 datacenter.
Powershell version: 5.1
The ultimate answer was that the character encoding for the CSV file I was using as input was causing problems for Powershell. Specifically, the line-ending encoding.
My original file was created on a Mac. The line-ending enconding was 'Macintosh (CR)'. The files that worked OK were created on this Windows machine, and used the line-ending encoding = "Windows (CR LF)".
Thanks to Olaf who got me thinking about this issue and made me investigate that area further.
I know there are question that is already answered however those are the log files I don't need and I can't get it to work. This part of PowerShell is something I didn't learned yet. I'm trying to do the following: I wrote a script to create users, mailboxes, folders etc however I want to enable a log file, just simple and plain.
Something only certain people can access and where the log files have the following info, for example: PSmith created on 01/29/2019 the user account JDoe.
How can I do this? I tried a lot found online however I have to rewrite my whole script for some to work.
Easiest option: you can enable transcript which would log every single command that is entered at the console potentially creating a huge file but you would have to filter for the specific messages yourself.
There are tools like microsoft orchestrator that would run your script and log the results automatically but those are expensive other than that you would pretty much have to build the logging yourself.
My suggestion would be to send the message to the windows event logs. This way you dont have to manage the log files, windows does it for you with date and time stamps. This would also make it audit and query friendly.
I believe you need something like this, if not please provide more code.
$creator = (get-aduser $env:username | Select Name).Name
$date = get-date -UFormat "%d/%m/%Y"
I believe you have the $user in your script.
$log = $creator + "created on " + $date + " the user account " + $user.Name
Out-File $log "C:\temp\log.csv"
I want to redirect all PowerShell cmdlet output except stream 1 (success) to a file. How can I achieve that? I know how to achieve to redirect individual stream, and I know how to merge it to standard output, but I don't want to mess standard output. I just want to capture streams 2,3 4 and (optionally) 5 into a single file. I am using Windows platform.
As example, I used these commands:
#('c:\temp\', 'c:\temp2\') | % {Get-ChildItem $_}
I do have c:\temp folder with some files inside, and I do not have c:\temp2 folder. So my expected output in file is to get only an error about missing folder temp2.
I tried assigning value to a variable, but it did not help. Normal assigning is not generating the output, but once redirected output appears.
($Files = #('c:\temp\', 'c:\temp2\') | % {Get-ChildItem $_}) *>err.txt
Without redirection, I see only error that c:\temp2 is not existing. But once redirected, list of files from C:\temp appears in err.txt. And, it appears at the end of file. Furthermore, assignment to $Files in ISE environment is not happening!? In other hosts, assignment works fine, but redirect is also adding files to output.
If I try to redirect as 3>err.txt 2>err.txt it fails with: The process cannot access the file err.txt because it is being used by another process.
Merging to any other stream except 1, is not supported. This attempt 3>&2 2>err.txt gives the error: The '3>&2' operator is reserved for future use.
I was able to do something with Start-Transcript, but that creates additional text, and its flooding the output file with unnecessary text.
I was reading following articles, but I did not find proper answer
about_redirection
Understanding Streams, Redirection, and Write-Host in PowerShell
Stack Overflow question: Redirect two or more Powershell streams other than output stream to the same file
A pragmatic workaround is to use the common -ov (-OutVariable) parameter, which enables collecting a cmdlet's success output in a variable, independently of how/whether the success stream is redirected:
'c:\temp\', 'c:\temp2\' | % { Get-ChildItem $_ } -ov Files 1>$null *>err.txt
# Get-ChildItem success output is now stored in $Files
1>$null suppresses the success stream
*>err.txt redirects the remaining streams to file err.txt
Note how Files rather than $Files is passed to -ov, because you must pass the name of the variable, not its value.
A caveat is that the variable specified for -ov receives the entire output and stores it in memory, which can be problematic with large output sets.
Also, as of PSv5.1, note that the output variable is invariably a [System.Collections.ArrayList] instance, even if only a single item was received.
This may change in v6.
As an aside, a more efficient reformulation of your command is:
Get-ChildItem c:\temp\, c:\temp2\ -ov Files 1>$null *>err.txt
I know the title sounds confusing, but once I describe this, I'm certain there is a very easy way to perform what I need to do. I'm very new to PowerShell and am trying to perform a specific task that seems rather difficult to find a good answer for one the Web.
I have spent the past several days searching through methods of concatenating the data and joining the files together, but nothing that was specific enough to this task. All examples show how to display data, but nothing that loops through and adds data together to create a new csv file. If anything, I've over-researched this issue to the point of having to pose this message to see where I can get my brain de-cluttered with all of the useless options I've already tried...
I have two csv files. I call them csv's, but they are really just a single column of information each.
Files:
Users.csv
Offices.csv
The Users.csv file has a list of network user names. The Offices.csv file has a list of numbers that correspond to office locations.
What I want to have happen is to use a loop that will take each user from the users.csv file and create a new line in a separate csv file the adds each of the offices to it.
EXAMPLE:
Users.csv
NTNAME
domain\user1
domain\user2
domain\user3
Offices.csv
OFFICES
0001
0023
0043
0067
When combined, I would like csv file that looks like this:
NTNAME,OFFICES
domain\user1,0001
domain\user1,0023
domain\user1,0043
domain\user1,0067
domain\user2,0001
domain\user2,0023
domain\user2,0043
domain\user2,0067
domain\user3,0001
domain\user3,0023
domain\user3,0043
domain\user3,0067
Any help you can give would be greatly appreciated...
Borrowing Shay's awesome CSV field enumeration code:
$offices = Import-Csv 'C:\path\to\offices.csv'
Import-Csv 'C:\path\to\users.csv' | % {
foreach ($prop in $_.PSObject.Properties) {
$offices | select #{n=$prop.Name;e={$prop.Value}}, OFFICES
}
} | Export-Csv 'C:\path\to\combined.csv' -NoTypeInformation
I am using powershell to automate some tasks related to checking out/merging in TFS. When I call
tf get * /recurse
I get a bunch of data scrolling by about the files that are getting checked out. The last line generated by this command (assuming its success) is one telling the checkin number. I would like to parse this out so it can be used later on in my script.
I know that I can do something like
$getOutput = tf get * /recurse
but then the output is suppressed entirely and I want the output of that command to be scrolled in realtime. I would basically like to grab everything that just got sent to the output buffer.
Try something like this:
tf get * /recurse | tee-Object -Variable getOutput
The tee-object in PowerShell 2.0 allows you to pipe results to two sources. If you leave the second source empty, the results go to the console.
ls | tee-object -filePath directoryListing.txt
This will write the directory listing to both the console and a text file.