I'm a SQL DBA, n00b to Powershell, tasked with sysadmin duties at the moment
I need to query error logs across my servers for Errors and Warnings.
Using my own Google-fu and help from this thread I was able to get this working:
$computers = Get-Content "C:\Servers\ServerList_Short.txt";
# QUERY COMPUTER SYSTEM EVENT LOG
foreach($computer in $computers)
{
Get-EventLog -ComputerName $computer -LogName System -EntryType "Error","Warning" -After (Get-Date).Adddays(-7) `
| Select-Object -Property machineName, EntryType, EventID, TimeGenerated, Message `
| Format-Table -Property MachineName, TimeGenerated, EntryType, Source, Message -AutoSize ;
}
What I am missing at the moment is how to trap for a server in my .txt file that is offline, ignore it and move to the next one. After that, I will be working to dump all of this to a SQL table, results.txt, etc.
Thanks for any help :)]
Kevin3NF
There are a few different ways to handle this but I'd recommend combining a Test-Connection with a Try/Catch, the Test-Connection will make it so that you only try to query the servers which respond to ping and then the Try/Catch will handle any other errors that may come along.
foreach($computer in $computers)
{
if(Test-Connection $computer -Quiet -Count 1){
Try {
Get-EventLog -ComputerName $computer -LogName System -EntryType "Error","Warning" -After (Get-Date).Adddays(-7) `
| Select-Object -Property machineName, EntryType, EventID, TimeGenerated, Message `
| Format-Table -Property MachineName, TimeGenerated, EntryType, Source, Message -AutoSize
} Catch {
Write-Verbose "Error $($error[0]) encountered when attempting to get events from $computer"
}
} else {
Write-Verbose "Failed to connect to $computer"
}
}
Related
I am trying to get all the list of KB installed on multiple servers and get the last reboot time of the system. My requirement is to get the result in csv or text format with column name "Hostname" , "KB Name" , "installed by" , "installed on" and "Last reboot". I have to execute 2 script to get this done and then i have to format it and i dont want other columns which i am receiving from code 1 only limited column are required.. Can some please help me to get the same format which i reuired?
Output required in below format :
"Source" "Description" "HotFixID" "InstalledBy" "InstalledOn" "Last Reboot"
Please find below 2 code.
FYI : I am new to powershell.
Code 1: This will list all KB installed patch.
$computers = Get-Content -path "C:\Users\joy\Desktop\Machine_List.txt"
$patches = Get-Content -path "C:\Users\joy\Desktop\KB_List.txt"
foreach ($computer in $computers){
foreach ($patch in $patches){
Get-HotFix -id $patch -ComputerName $computer | -OutVariable results -ErrorAction SilentlyContinue
if ($results -ne $null) {
$results | Out-File C:\Users\joy\Desktop\report1.txt -Append -Force
}
else {
Add-content "$Patch is not Present in $computer" -path "C:\Users\joy\Desktop\report2.txt"
}
}
Code 2: This will get the last reboot of the system.
$machines = Get-Content C:\Users\joy\Desktop\Machine_List.txt
$report = #()
$object = #()
foreach($machine in $machines)
{
$machine
$object = gwmi win32_operatingsystem -ComputerName $machine | select csname, #{LABEL='LastBootUpTime';EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)}}
$report += $object
}
$report | Export-csv C:\Users\joy\Desktop\Reboot.csv
$computers = Get-Content C:\Users\XXXXXXXX\Desktop\Machine_List.txt
$patchlist = Get-Content C:\Users\XXXXXXXX\Desktop\KB_List.txt
foreach($computer in $computers)
{
Get-HotFix -ComputerName $computer -Id $patchlist | select
InstalledOn,InstalledBy,Description,HotFixID,__SERVER | Format-Table | Out-File
C:\Users\XXXXXXXX\Desktop\report1.txt
#Get-CimInstance -ClassName Win32_Operatingsystem | select csname, lastbootuptime |
Format-Table |Out-File C:\Users\XXXXXXXX\Desktop\report1.txt
gwmi win32_operatingsystem -ComputerName $computer | select csname,
#{LABEL='LastBootUpTime';EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)}} | Out-
File C:\Users\XXXXXXXX\Desktop\report1.txt -Append
}
Try this, This will allow you to get information what you are looking for. But this script only get installed patches information from the remote machines, If you want add one more loop to print the patches which are installed on another text file.
This thread got me started very well, but now I need more help
I am trying to loop through my serverlist.txt file, and pass the results of Get-EventLog to Out-GridView and then on to a .csv file. I have this working, but I have to select all the records in the GridView window then click OK for each server.
So, I have the idea that I want to create a $sys variable outside the loop, go in, append the results to that variable for each server, and then exit the loop and pass $sys over to Grid-view.
My confusion comes regardinf variable declaration, type, appending and placement in the code...
I'm just learning PS now, so this may be a little basic for you :)
this code works...need to add in the variable idea in the right places:
#Drop the existing files
Remove-Item C:\system.csv
# SERVER LIST PROPERTIES
# Get computer list to check disk space. This is just a plain text file with the servers listed out.
$computers = Get-Content "C:\ServerList.txt";
#Declare $sys here ??
# QUERY COMPUTER SYSTEM EVENT LOG
foreach($computer in $computers)
{
if(Test-Connection $computer -Quiet -Count 1)
{
Try {
# $sys =
Get-EventLog -ComputerName $computer -LogName System -EntryType "Error","Warning" -After (Get-Date).Adddays(-7) `
| Select-Object -Property machineName, EntryType, EventID, Source, TimeGenerated, Message `
| Out-GridView -PassThru | Export-Csv C:\System.csv -NoTypeInformation -Append;
}
Catch
{
Write-Verbose "Error $($error[0]) encountered when attempting to get events from $computer"
}
}
else {
Write-Verbose "Failed to connect to $computer"
}
}
# $sys | Out-GridView....etc.
Thanks!
Kevin3NF
Just to close this out, I used suggestions from mutiple comments:
$sys = #() (outside the loop)
$sys += Get-EventLog (inside the loop)
$sys | Export-Csv (after the loop to send to .csv)
I even blogged the whole thing, including all the various iterations of learning I went through:
http://dallasdbas.com/getting-to-know-powershell-from-an-old-dba/
Thanks to all that helped. This gave me a framework I will continue to use on these servers as the needs arise.
Kevin3NF
I have a working script that is able to pull a report of Windows Application, Security, Setup and System logs that displays only the critical and error events in the past 30 days. However, I would also really like the script to count the number of times each reported critical or error event occurred in the past 30 days. Here's the working command:
Get-EventLog Application -ComputerName $server -After $starttime |
? { $_.entryType -Match "Error" -and "Critical" } |
Sort-Object EventID -Unique |
Select-Object TimeGenerated,EventID,Source,Message |
ft -AutoSize -Wrap |
Out-File $file -Append
And here is an example of the output in the text file:
TimeGenerated EventID Source Message
------------- ------- ------ -------
7/8/2016 1:23:20 PM 0 SQL Server Report Service Service cannot be started. Microsoft.ReportingS
ervices.Diagnostics.Utilities.InternalCatalogEx
ception: An internal error occurred on the repo
rt server. See the error log for more details.
at Microsoft.ReportingServices.Library.Nativ
e.GetSid(String name, Int32& length)
at Microsoft.ReportingServices.Library.Nativ
e.NameToSid(String name)
at Microsoft.ReportingServices.Library.Servi
ceAppDomainController.StartRPCServer(Boolean fi
rstTime)
at Microsoft.ReportingServices.Library.Servi
ceAppDomainController.Start(Boolean firstTime)
at Microsoft.ReportingServices.NTService.Rep
ortService.OnStart(String[] args)
at System.ServiceProcess.ServiceBase.Service
QueuedMainCallback(Object state)
7/8/2016 1:23:20 PM 121 Report Server Windows Service (MSSQLSERVER) The Remote Procedure Call (RPC) service failed
to start.
It would be great to have another column in the results that displays the occurrences of each EventID in the specified time period.
You could do it like so (line 3 & 4 are new and Count in Select-Object)
Technically you could also remove the -Unique from Sort-Object as after grouping them and passing through only the first item of the group is more or less the same.
Get-EventLog Application -ComputerName $server -After $starttime |
? { $_.entryType -Match "Error" -and "Critical" } |
Group-Object -Property EventID |
% { $_.Group[0] | Add-Member -PassThru -NotePropertyName Count -NotePropertyValue $_.Count } |
Sort-Object EventID -Unique |
Select-Object Count, TimeGenerated, EventID, Source, Message |
ft -AutoSize -Wrap |
Out-File $file -Append
i need to compare status of many services and each dependancy on many remote computer for restart it if needed.
but the output of get-service is poor in CLI
You can pipe get-service with Out-GridView, get-service accept a list of computerName.
get-service -computerName PC1,PC2 | Out-GridView -OutputMode Multiple | Restart-Service -force -passthru
the function Out-gridView provide a very good user interface.
function restartRmService {
param (
[Parameter(Mandatory=$true,Position=0)]
[Alias("CN")]
[string[]]$ComputerName,
[Parameter(Mandatory=$false)]
[Alias("CN")]
[string[]]$serviceName
)
$Restart = #()
if ($serviceName) {
$Restart = Get-Service -ComputerName ($ComputerName | select-Object -unique) -name $serviceName | select *
}
else {
$Restart = Get-Service -ComputerName ($ComputerName | select-Object -unique) | select MachineName, ServiceName, Status, DisplayName, DependentServices, ServicesDependedOn | Out-GridView -OutputMode Multiple -Title 'Selectionner les Services a Redemarer, puis valider'
}
$Restart | %{
$status = (Get-Service -ComputerName $_.MachineName -ServiceName $_.ServiceName | Restart-Service -force -passthru | select *).status
}
}
I'm having issue with a script I've written and would love some help.
Please note I'm very new to powershell.
I've written a script that uses a txt file that contains remote computers on a domain, I appears to be working to some degree but in the event of a machine being offline I get errors which then loop the script.
$machines
$pcname
Name = 'Machine'
Expression = { $_.PsComputerName }
}
ForEach ($System in $Machines)
{
#Pings machine's found in text file
if (!(test-Connection -ComputerName $System -BufferSize 16 -Count 1 -ea 0 -Quiet))
{
Write-Output "$System Offline"
}
Else
{
#Providing the machine is reachable
#Checks installed programs for products that contain Kaspersky in the name
gwmi win32_product -Filter {Name like "%Kaspersky%"} -ComputerName $Machines | Select-Object -Property $pcname,Name,Version
}
}
At present this runs and output's like so:
Machine Name Version
UKTEST01 Kaspersky Security Center Network Agent 10.1.249
UKTEST02 Kaspersky Endpoint Security 10 for Windows 10.2.1.23
But in the event of a machine not being reachable the following error is given:
gwmi : The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
At C:\Scripts\Powershell\Kaspersky Endpoint Security 10\Script\New folder\Kaspersky Checker working v2.ps1:15 char:9
+ gwmi win32_product -Filter {Name like "%Kaspersky%"} -ComputerName $Mach ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
+ FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
And then moves to the next machine in the list, and then repeats from the beginning again.
I'd like for this to simply show as:
UKTEST03 Offline
And stop once the last machine in the txt file is done.
Any help or advise would be greatly appreciated.
This is the perfect time to use a Try/Catch/Finally block. The flow is this : Try the block of code here, if you encounter an error, suppress the message and do what is in the Catch block instead.
I've modified your code a bit, so simply copy this whole code block and drop it in, replacing your Else {scriptblock} in your original code.
Else
{
#Providing the machine is reachable
#Checks installed programs for products that contain Kaspersky in the name
Try {Get-WMIObject -Class win32_product -Filter {Name like "%Kaspersky%"} `
-ComputerName $Machines -ErrorAction STOP |
Select-Object -Property $pcname,Name,Version }
Catch {#If an error, do this instead
Write-Output "$system Offline }
}
}
Your completed answer
I've folded in the change you requested, to keep your script from running on every machine in $machines instead of $system, as you likely intended.
ForEach ($System in $Machines){
#Pings machine's found in text file
if (!(test-Connection -ComputerName $System -BufferSize 16 -Count 1 -ea 0 -Quiet))
{
Write-Output "$System Offline"
}
Else
{
#Providing the machine is reachable
#Checks installed programs for products that contain Kaspersky in the name
Try {Get-WMIObject -Class win32_product -Filter {Name like "%Kaspersky%"} `
-ComputerName $System -ErrorAction STOP |
Select-Object -Property $pcname,Name,Version }
Catch {#If an error, do this instead
Write-Output "$system Offline "}
#EndofElse
}
#EndofForEach
}
You could try this:
$machines=... # your machines' names
foreach ($machine in $machines)
{
trap{"$machine`: not reachable or not running WsMan";continue}
if(test-wsman -ComputerName $machine -ea stop){
gcim -Class CIM_Product -Filter 'Name like "%Kaspersky%"' |
select pscomputername,name,version
}
}
I'm using gcim because gwmi is deprecated.
Correction: the correct name is Kaspersky; I corrected it.