need some help with this bit of code. So I have got some powershell that is called from a bit of code as below:
powershell -file "E:\crs\shared\utils\EventViewerExport\EventViewerExport.ps1" "BAUT101,BAUT103,BAUT105,BAUT106,BAUT107,BAUT108,BAUT109,BAUT010"
The powershell code that the above calls is below:
#List of servers:
$ArraySvr = $args[0].split(",") ;
foreach ($Server in $ArraySvr){
$args = #{}
$args.Add("StartTime", ((Get-Date).AddMinutes(-160)))
$args.Add("EndTime", (Get-Date))
$args.Add("LogName", "System")
$args.Add("ID",7001)
Get-WinEvent -FilterHashtable $args -ComputerName $Server | select MachineName,LogName,LevelDisplayName,TimeCreated,ProviderName,ID,#{n='Message';e={(New-Object System.Security.Principal.SecurityIdentifier $Log.ReplacementStrings[1]).Translate([System.Security.Principal.NTAccount])}} | export-csv -Delimiter '|' -Path E:\crs\shared\utils\EventViewerExport\EventViewerExportFile.csv -Append -Force
}
The script is almost 100% perfect, except the "Message" column isn't pulling through the the CSV file while its in the foreach function.
My csv file looks like this:
#TYPE Selected.System.Diagnostics.Eventing.Reader.EventLogRecord
"MachineName"|"LogName"|"LevelDisplayName"|"TimeCreated"|"ProviderName"|"Id"|"Message"
"BAUT101.compname.adp"|"System"|"Information"|"03/03/2022 18:03:15"|"Microsoft-Windows-Winlogon"|"7001"|
However the Message column does pull through when I take out the foreach function, as below:
$args = #{}
$args.Add("StartTime", ((Get-Date).AddMinutes(-160)))
$args.Add("EndTime", (Get-Date))
$args.Add("LogName", "System")
$args.Add("ID",7001)
Get-WinEvent -FilterHashtable $args -ComputerName 'BAUT101' | select MachineName,LogName,LevelDisplayName,TimeCreated,ProviderName,ID,#{n='Message';e={(New-Object System.Security.Principal.SecurityIdentifier $Log.ReplacementStrings[1]).Translate([System.Security.Principal.NTAccount])}} | export-csv -Delimiter '|' -Path E:\crs\shared\utils\EventViewerExport\EventViewerExportFile.csv -Append -Force
By running this set of code with the foreach function, I get the correct csv export:
#TYPE Selected.System.Diagnostics.Eventing.Reader.EventLogRecord
"MachineName"|"LogName"|"LevelDisplayName"|"TimeCreated"|"ProviderName"|"Id"|"Message"
"BAUT101.compname.adp"|"System"|"Information"|"03/03/2022 18:03:15"|"Microsoft-Windows-Winlogon"|"7001"|"compname\djgood"
Does anyone know why on earth the Message column won't export when I'm running the powershell with an array of servers, but it will when I query a specific computer name?
Can anyone help me out please?
Thanks in advance.
Data mapping project, in house system to new vendor system. First step is find all the occurrences of current database field names (or column names to be precise) in the C# .cs source files. Trying to use Powershell. Have recently created PS searches with Get-ChildItem and Select-String that work well but the search string array was small and easily hard coded inline. But the application being ported has a couple hundred column names and significant amounts of code. So armed with a text file of all the column names Pipleline would seem like a god tool to create a the basic cross ref for further analysis. However, I was not able to get the Pipeline to work with an external variable anyplace other than first step. Trying using -PipelineVariable, $_. and global variable. Did not find anything specific after lots of searching. P.S. This is my first question to StackoOverflow, be kind please.
Here is what I hoped would work but do dice so far.
$inputFile = "C:\DataColumnsNames.txt"
$outputFile = "C:\DataColumnsUsages.txt"
$arr = [string[]](Get-Content $inputfile)
foreach ($s in $arr) {
Get-ChildItem -Path "C:ProjectFolder\*" -Filter *.cs -Recurse -ErrorAction SilentlyContinue -Force |
Select-String $s | Select-Object Path, LineNumber, line | Export-csv $outputfile
}
Did find that this will print the list one time but not twice. In fact it seems using the variable in this way results in processing simply skipping any further pipeline steps.
foreach ($s in $arr) {Write-Host $s | Write $s}
If it isn't possible to do this in Powershell easily my fallback is to do with C# although would much rather get the level up with PowerShell if anyone can point me to the correct understanding of how to do things in the Pipepline, or alternatively construct an equivalent function. Seems like such a natural fit for Powershell.
Thanks.
You're calling Export-csv $outputfile in a loop, which rewrites the whole file in every iteration, so that only the last iteration's output will end up in the file.
While you could use -Append to iteratively append to the output file, it is worth aking a step back: Select-String can accept an array of patterns, causing a line that matches any of them to be considered a match.
Therefore, your code can be simplified as follows:
$inputFile = 'C:\DataColumnsNames.txt'
$outputFile = 'C:\DataColumnsUsages.txt'
Get-ChildItem C:\ProjectFolder -Filter *.cs -Recurse -Force -ea SilentlyContinue |
Select-String -Pattern (Get-Content $inputFile) |
Select-Object Path, LineNumber, line |
Export-csv $outputfile
-Pattern (Get-Content $inputFile) passes the lines of input file $inputFile as an array of patterns to match.
By default, these lines are interpreted as regexes (regular expressions); to ensure that they're treated as literals, add -SimpleMatch to the Select-String call.
This answer to a follow-up question shows how to include the specific pattern among the multiple ones passed to -Pattern that matched on each line in the output.
I think you want to append each occurrence to the csv file. And you need to get the content of the file. Try this:
$inputFile = "C:\DataColumnsNames.txt"
$outputFile = "C:\DataColumnsUsages.txt"
$arr [string[]](Get-Content $inputfile)
foreach ($s in $arr) {
Get-ChildItem -Path "C:ProjectFolder\*" -Filter *.cs -Recurse -ErrorAction SilentlyContinue -Force | Foreach {
Get-Content "$_.Fullname" | Select-String $s | Select-Object Path, LineNumber, line | Export-csv -Append -Path "$outputfile"
}
}
-Append was not introduced before powershell v3.0 (Windows 8) then try this:
$inputFile = "C:\DataColumnsNames.txt"
$outputFile = "C:\DataColumnsUsages.txt"
$arr [string[]](Get-Content $inputfile)
foreach ($s in $arr) {
Get-ChildItem -Path "C:ProjectFolder\*" -Filter *.cs -Recurse -ErrorAction SilentlyContinue -Force | Foreach {
Get-Content "$_.Fullname" | Select-String $s | Select-Object Path, LineNumber, line | ConvertTo-CSV -NoTypeInformation | Select-Object -Skip 1 | Out-File -Append -Path "$outputfile"
}
}
I have a simple text file that looks like this...
A,400000051115,null,null,null,null,null,null,null,20190312,090300,Answer Machine,2019,3,14,10,0
A,400000051117,null,null,null,null,null,null,null,20190312,090300,Confirmed,2019,3,14,10,30
A,400000051116,null,null,null,null,null,null,null,20190312,090300,Answer Machine,2019,3,14,11,0
A,400000051114,null,null,null,null,null,null,null,20190312,090300,Wants to Cancel,2019,3,14,9,0
A,400000051117,null,null,null,null,null,null,null,20190312,091800,SMS Sent,2019,3,14,10,30
A,400000051116,null,null,null,null,null,null,null,20190312,091800,SMS Sent,2019,3,14,11,0
A,400000051115,null,null,null,null,null,null,null,20190312,091800,SMS Sent,2019,3,14,10,0
A,400000051116,null,null,null,null,null,null,null,20190312,093000,Appointment Cancelled/Rescheduled Via SMS,2019,3,14,11,0
I need to save all the lines except those that have "SMS Sent" in them to a new file. I am using the following...
get-content $SourceFile.FullName | select-string -pattern 'SMS Sent' -notmatch | Out-File $targetFile
Why in the resulting file do I get a blank first line?
If you change Out-File $targetFile to Out-Host or even just omit that last segment in the pipeline, you will see a blank line in the console output, too.
The output analog of Get-Content is Set-Content, so if you change Out-File $targetFile to Set-Content $targetFile the first line is no longer blank.
Also, since you're working with a CSV file you could use Import-CSV to read the data and Where-Object to filter on that specific column, although a little extra work is required to specify the headers and omit them from the output file...
$csvHeaders = 1..17 | ForEach-Object -Process { "Column $_" }
$csvHeaders[11] = 'Status'
Import-Csv -Path $SourceFile.FullName -Header $csvHeaders `
| Where-Object -Property 'Status' -NE -Value 'SMS Sent' `
| ConvertTo-Csv -NoTypeInformation `
| Select-Object -Skip 1 `
| Set-Content $targetFile
...which writes...
"A","400000051115","null","null","null","null","null","null","null","20190312","090300","Answer Machine","2019","3","14","10","0"
"A","400000051117","null","null","null","null","null","null","null","20190312","090300","Confirmed","2019","3","14","10","30"
"A","400000051116","null","null","null","null","null","null","null","20190312","090300","Answer Machine","2019","3","14","11","0"
"A","400000051114","null","null","null","null","null","null","null","20190312","090300","Wants to Cancel","2019","3","14","9","0"
"A","400000051116","null","null","null","null","null","null","null","20190312","093000","Appointment Cancelled/Rescheduled Via SMS","2019","3","14","11","0"
...to $targetFile. Note that all of the values are quoted now. If your input file does have headers then you could use simply...
Import-Csv -Path $SourceFile.FullName `
| Where-Object -Property 'Status' -NE -Value 'SMS Sent' `
| Export-Csv -NoTypeInformation -LiteralPath $targetFile
In either case the output file will not contain a leading blank line.