I am having an issue with the writing of a get-eventlog function when I'm writing to a TXT file.
This is my LogWrite function:
#Log Function
$Logfile = "..\Logs\$(gc env:computername)_Outlook.log"
$Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")
Function LogWrite
{
Param ([string]$logstring)
Add-content $Logfile -value $Stamp": "$logstring -Force
}
This is my LogWrite code in part of my script.
$OutlookHangDetailed = Get-EventLog -Log "Application" -Source "Application Hang" -Message "*OUTLOOK.EXE*" -After (Get-Date).AddHours(-12) -ErrorAction SilentlyContinue
LogWrite $OutlookHangDetailed | Format-List
The issue I am having is its coming out like this in the txt file:
Microsoft.PowerShell.Commands.GenericMeasureInfo
But if I simply echo it, it comes out like this (This is an example):
Index : 2568
EntryType : Information
InstanceId : 15
Message : Updated Symantec Endpoint Protection status successfully to SECURITY_PRODUCT_STATE_ON.
Category : (0)
CategoryNumber : 0
ReplacementStrings : {Symantec Endpoint Protection, SECURITY_PRODUCT_STATE_ON}
Source : SecurityCenter
TimeGenerated : 3/15/2017 7:46:02 AM
TimeWritten : 3/15/2017 7:46:02 AM
How can I get this to write to the log this way?
There is no output from your log function. You are not piping anything into Format-List
$OutlookHangDetailed is going to be an array of objects of [System.Diagnostics.EventLogEntry]. You can turn it into a string with $logstring | fl | out-string. Casting directly to a string isn't going to give you the output you are looking for.
$Logfile = "..\Logs\$(gc env:computername)_Outlook.log"
$Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")
Function LogWrite {
Param (
[System.Diagnostics.EventLogEntry[]]$logstring,
[string]$Logfile,
[string]$Stamp
)
$logentry = "$($Stamp):$($logstring | fl | out-string)"
Add-Content $Logfile -value $logentry -Force
$logentry
}
$OutlookHangDetailed = Get-EventLog -Log "Application" -Source "Application Hang" -Message "*OUTLOOK.EXE*" -After (Get-Date).AddHours(-12) -ErrorAction SilentlyContinue
LogWrite $OutlookHangDetailed $Logfile $Stamp
Get-EventLog -Log "Application" -Source "Application Hang" -Message "*OUTLOOK.EXE*" -After (Get-Date).AddHours(-12) -ErrorAction SilentlyContinue >> "..\Logs\$(gc env:computername)_Outlook.log"
This will work as expected
Maybe like this:
Function LogWrite
{
param (
$logstring
)
$Stamp | Out-File -Encoding UTF8 -FilePath $Logfile -Append -Force
($logstring | Format-List) | Out-File -Encoding UTF8 -FilePath $Logfile -Width 1024 -Append -Force
}
And call your function with:
LogWrite $OutlookHangDetailed
Related
I really need your help, I already make a script for export logs to csv file:
Set-Variable -Name EventAgeDays -Value 1
Set-Variable -Name CompArr -Value #("Localhost")
Set-Variable -Name LogNames -Value #("Security", "Application", "System")
Set-Variable -Name EventTypes -Value #("Information", "Error", "Warning", "FailureAudit", "SuccessAudit")
Set-Variable -Name ExportFolder -Value "C:\"
$el_c = #()
$now = [System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId($(Get-Date), [System.TimeZoneInfo]::Local.Id, 'GMT Standard Time')
$startdate=$now.adddays(-$EventAgeDays)
$ExportFile=$ExportFolder + "mx_sugus_poc_" + $now.ToString("yyyy.MM.dd_hh.mm") + ".csv"
foreach($comp in $CompArr)
{
foreach($log in $LogNames)
{
Write-Host Processing $comp\$log
$el = get-eventlog -ComputerName $comp -log $log -After $startdate -EntryType $EventTypes -Message "*"
$el_c += $el
}
}
$el_sorted = $el_c | Sort-Object TimeGenerated
Write-Host Exporting to $ExportFile
$el_sorted|Select TimeGenerated, EntryType, Source, EventID, MachineName, UserName, Message | export-CSV $ExportFile -NoTypeInfo
Additional I change the date for a GMT format.
I want to change the search in my logs instead of every day for every hour.
Can you help me with this ???
Thanks so much !!!
Change $startdate=$now.adddays(-$EventAgeDays) to $startdate=$now.addHours(-1)
I'm trying to get a set instructions to wait until a process is finished before they start but I keep having the variables try to run straight after.
I would try a wait() but I cant know how long the scan will take.
#Variables
$logPath = "C:\Users\Administrator\Desktop\log.txt"
$scanPath = "C:\Users\Administrator\Desktop\scan.txt"
$repairLog = "C:\Users\Administrator\Desktop\repair.txt"
$failLog = "C:\Users\Administrator\Desktop\fail.txt"
$computer = "SERVER2012"
$CBSFileLocation = "C:\Windows\Logs\CBS\CBS.log"
$date = Get-Date
$sevenDays = New-Object System.TimeSpan 7,0,0,0,0
$repair = "Repair"
$fail = "fail"
$then = $date.Subtract($sevenDays)
#Start of Code:
$EventLog = Get-EventLog -LogName System -ComputerName $computer -After $then -Before $date -EntryType Error | Out-File $logPath
Start-Job -Name SFC {Start-Process sfc /scannow}
#I want the wait/suspend here.
Wait-Job -Name SFC {
$ScanX = Get-Content $CBSFileLocation
$ScanX | Out-File $scanPath
Select-String -Path $scanPath -Pattern $repair | Out-File $repairLog
Select-String -Path $scanPath -Pattern $fail | Out-File $failLog
echo "Done!!"
}
I'm guessing you want to wait, and when SFC is ready, execute the script inside the last { ... } in your scripts.
As far as I can tell from reading the documentation for Wait-Job, there is no scriptblock parameter what would allow for this.
Instead try rearranging your code a little, like this
#Variables
$logPath = "C:\Users\Administrator\Desktop\log.txt"
$scanPath = "C:\Users\Administrator\Desktop\scan.txt"
$repairLog = "C:\Users\Administrator\Desktop\repair.txt"
$failLog = "C:\Users\Administrator\Desktop\fail.txt"
$computer = "SERVER2012"
$CBSFileLocation = "C:\Windows\Logs\CBS\CBS.log"
$date = Get-Date
$sevenDays = New-Object System.TimeSpan 7,0,0,0,0
$repair = "Repair"
$fail = "fail"
$then = $date.Subtract($sevenDays)
#Start of Code:
$EventLog = Get-EventLog -LogName System -ComputerName $computer -After $then -Before $date -EntryType Error | Out-File $logPath
#Start the job and return the prompt once the job has State Completed
Start-Job {Start-Process sfc /scannow} | Wait-Job
#These lines are executed once Wait-Job above returns the prompt
$ScanX = Get-Content $CBSFileLocation
$ScanX | Out-File $scanPath
Select-String -Path $scanPath -Pattern $repair | Out-File $repairLog
Select-String -Path $scanPath -Pattern $fail | Out-File $failLog
echo "Done!!"
I wanted to start a new thread for this, since I am using a different method in my code now. I have written a script that pings hundreds of devices and logs their online or offline status. It was taking an extremely long time to run, so I am now looking into using Invoke-Command to run the commands remotely on servers for each site (instead of all from the same server). I am receiving the following errors: "A positional parameter cannot be found that accepts argument 'Of'", "You cannot call a method on a null-valued expression", and this is happening for each server as it is iterating through them. Any ideas as to why this is happening? Thank you very much, here is my current code:
<#
.NOTES
===========================================================================
Created on: 11/17/2016 8:06 AM
Created by:
Organization:
Filename: Get-MPOSOfflinePrinters.ps1
===========================================================================
.DESCRIPTION
#>
#Define log file variables and remove any existing logs
$logfile = "D:\Logs\MPOSPrinterPingLog.txt"
$offlineprinters = "D:\Reports\MPOS\MPOSOfflinePrinters.txt"
If (Test-Path $logfile) {Remove-Item $logfile}
If (Test-Path $offlineprinters) {Remove-Item $offlineprinters}
Add-Content $logfile "Gathering server list"
#Compiling list of all MPOS Print Servers
$serverList = (Get-ADComputer -Filter "Name -like 'Q0*P30' -or Name -like 'Q0*P32'" -SearchBase "OU=Print,OU=Prod,OU=POS,DC=COMPANY,DC=NET").name | Sort-Object | Out-File C:\Temp\MPOS\MPOSPrintServers.txt
$serverListPath = "C:\Temp\MPOS\MPOSPrintServers.txt"
Add-Content $logfile "Compiling text file"
#Retrieve a list of MPOS Print servers from text file and set to variable $serverNames
$serverNames = Get-Content -Path $serverListPath
Invoke-Command -ComputerName $serverNames -ScriptBlock {
#Define log file variables and remove any existing logs
$logfile = "C:\Temp\MPOSPrinterPingLog.txt"
$offlineprinters = "C:\Temp\MPOSOfflinePrinters.txt"
$masteroffline = "\\a0345p689\d$\Reports\MPOS\MPOSOfflinePrinters.txt"
If (Test-Path $logfile) {Remove-Item $logfile}
If (Test-Path $offlineprinters) {Remove-Item $offlineprinters}
#process xml file to parse IP addresses for ping
$timestamp2 = (Get-Date -Format g)
Add-Content $logfile "$timestamp2 - Processing xml file from $serverName to parse data to csv"
$xml = [xml](Get-Content C:\ProgramData\Microsoft\Point Of Service\Configuration\Configuration.xml)
$PrinterNames = $xml.selectNodes('//PointOfServiceConfig/ServiceObject/Device') | foreach {New-Object -TypeName psobject -Property #{LogicalName=$_.LogicalName.Name}}
$PrinterIPs = $xml.selectNodes('//PointOfServiceConfig/ServiceObject/Device') | foreach {New-Object -TypeName psobject -Property #{HardwarePath=$_.HardwarePath}}
foreach ($PrinterIP in $PrinterIPs) {
$pingableIP = $PrinterIP.HardwarePath
If (Test-Connection $pingableIP -Quiet -Count 1) {
$timestamp3 = (Get-Date -Format g)
Add-Content $logfile "$timestamp3 - $serverName, $pingableIP is online and pingable"
}
Else {
$timestamp3 = (Get-Date -Format g)
Add-Content $offlineprinters "$timestamp3 - $serverName, $pingableIP is offline!"
}
Get-Content $offlineprinters | Out-File -FilePath $masteroffline -Append -NoClobber
} #foreach ($PrinterIP in $PrinterIPs) {
} #Invoke-Command -ComputerName $serverNames -ScriptBlock {
I have inherited a script that is not working. I need to capture everything that would normally output to the console, including Success and Error entries from the script. This is only a small portion of the script, and it only captures errors. Any help would be appreciated on getting all output to the file instead of the console.
An example is the Write-Verbose "VERIFYING contact for $($User.WindowsEmailAddress)"
I know this is writing to the console, but I need it to write to the log that is defined at the very bottom of the script.
Catch
{Out-File -InputObject "$(Get-Date -Format MM.dd.yyyy-HH:mm:ss);$($WriteMode);ERROR;Target;$($targetUser.Split('#')[1]);$($User.WindowsEmailAddress);Update;;;Error updating user: $($Error[0])" -FilePath $LogFilePath -Append}
I hope this makes sense.
### UPDATES
ForEach ($User in $colUpdContact)
{
Write-Verbose "VERIFYING contact for $($User.WindowsEmailAddress)"
#Filter used to find the target contact object(s)
$strFilter = "WindowsEmailAddress -eq `"$($User.WindowsEmailAddress)`""
Try
{$colContacts2 = Invoke-Command -Session $targetSession -ScriptBlock {param ($strFilter) Get-Contact -Filter $strFilter} -ArgumentList $strFilter -ErrorAction Stop}
Catch
{Out-File -InputObject "$(Get-Date -Format MM.dd.yyyy-HH:mm:ss);$($WriteMode);ERROR;Target;$($targetUser.Split('#')[1]);$($User.WindowsEmailAddress);Find;;;Error getting contact: $($Error[0])" -FilePath $LogFilePath -Append}
ForEach ($Contact in $colContacts2)
{
#initialize update string and cmd string
$strUpdateContact = $null
$updateCmd = $null
$strWriteBack = $null
$writeBackCmd = $null
#Iterate through attributes and append to the strUpdateContact string if the attribute value has changed
ForEach ($Attrib in $arrAttribs)
{
If ($User.$Attrib -ne $Contact.$Attrib)
{
if($ReadOnly){
Add-Content -Path $readOnlyFilePath -Value " Changing $Attrib"
Add-Content -Path $readOnlyFilePath -Value " Before: $($Contact.$Attrib)"
Add-Content -Path $readOnlyFilePath -Value " After: $($User.$Attrib)"
}
$strUpdateContact += " -$($Attrib) `"$($User.$Attrib)`""
Out-File -InputObject "$(Get-Date -Format MM.dd.yyyy-HH:mm:ss);$($WriteMode);CHANGE;Target;$($targetUser.Split('#')[1]);$($User.WindowsEmailAddress);Update;$($Contact.$Attrib);$($User.$Attrib);" -FilePath $LogFilePath -Append
}
}
#Check if LegacyExchangeDN has been written back to User object
$mailContact = Invoke-Command -Session $targetSession -ScriptBlock {param ($contact) Get-MailContact $($contact.WindowsEmailAddress)} -ArgumentList $Contact -ErrorAction Stop
$x500 = "X500:$($mailContact.LegacyExchangeDN)"
$userRec = Invoke-Command -Session $sourceSession -ScriptBlock {param ($User) Get-Recipient $($User.WindowsEmailAddress)} -ArgumentList $User -ErrorAction Stop
if($UserRec.emailAddresses -notcontains $x500){
$userName = ($user.UserPrincipalName).Split('#')[0]
if($userName -eq "")
{
$userName = $user.SamAccountName
}
$strWriteBack = "Set-ADUser -Identity $userName -Add #{ProxyAddresses=`"$x500`"} -Server $sourceDC -Credential `$sourceDCCredential"
}
#If there is anything to update
If ($strUpdateContact.Length -gt 0)
{
Write-Verbose "Updating attributes for $($User.WindowsEmailAddress)"
#Prepend the command for the contact being modified
$strUpdateContact = "Set-Contact $($User.WindowsEmailAddress) " + $strUpdateContact
If ($ReadOnly)
{Add-Content -Path $readOnlyFilePath -Value $strUpdateContact}
Else
{
Try
{
#Create the complete command and invoke it
$updateCmd = "Invoke-Command -Session `$targetSession -ScriptBlock {$($strUpdateContact)}"
Invoke-Expression $updateCmd -ErrorAction Stop
}
Catch
{Out-File -InputObject "$(Get-Date -Format MM.dd.yyyy-HH:mm:ss);$($WriteMode);ERROR;Target;$($targetUser.Split('#')[1]);$($User.WindowsEmailAddress);Update;;;Error updating contact: $($Error[0])" -FilePath $LogFilePath -Append}
}
}
If ($strWriteBack){
Write-Verbose "Updating X500 for $($User.WindowsEmailAddress)"
Out-File -InputObject "$(Get-Date -Format MM.dd.yyyy-HH:mm:ss);$($WriteMode);CHANGE;Target;$($targetUser.Split('#')[1]);$($User.WindowsEmailAddress);Update;;$x500;" -FilePath $LogFilePath -Append
If($ReadOnly){
Add-Content -Path $readOnlyFilePath -Value $strWriteBack
}
else{
Try
{
Invoke-Expression $strWriteBack -ErrorAction Stop
}
Catch
{Out-File -InputObject "$(Get-Date -Format MM.dd.yyyy-HH:mm:ss);$($WriteMode);ERROR;Target;$($targetUser.Split('#')[1]);$($User.WindowsEmailAddress);Update;;;Error updating user: $($Error[0])" -FilePath $LogFilePath -Append}
}
}
}
}
Why you not use the Start-Transcript to output all the information into a log file, and then you can manually copy anything you want?
An example for the command:
Start-Transcript -Path $TranscriptOutputFile -Append -Force
#Your script; write-output 'something update';
Stop-Transcript
Everything output by write-output command will be appended into the log file.
So say you want to look at the last 3 thing in the eventlog for type application, from all the desktops on the lan. my problem is, the $a below makes an array (i think), and i want to write that to a file. right now it "works" but just spits out a few blank lines per machine. if $msg = is commented out, i get this "Exception calling "Join" with "2" argument(s): "Value cannot be null."
$servers = "machine1, "machine2"
$date = ( get-date ).ToString('yyyyMMdd')
$file = New-Item -type file "c:\temp\$date-test1.txt" -Force
$msg = ""
foreach($server in $servers){
Write-Host "Connect to $server..."
add-content $file "$server $date"
$a = Get-EventLog -Logname application -ComputerName $server -EntryType warning -newest 3 |
Format-Table -Wrap -Property Source,Message -Autosize
foreach($element in $a)
{[string]::join($element, $msg)}
Write-Host $msg
#add-content $file $msg
}
You are thinking about text, not objects in the pipeline. Don't try to parse, join or mess around with strings.
$servers = "machine1, "machine2"
$date = ( get-date ).ToString('yyyyMMdd')
$file = New-Item -type file "c:\temp\$date-test1.txt" -Force
Get-EventLog -log Application -Computer $servers -entry Warning -newest 3 | Select MachineName,Source,Message | out-file $file