How can I make this use a list of servers
Tried doing $ComputerList = gc <list location> but it doesnt seem to be working
correctly with one computer
$Start = (Get-Date).AddMinutes(-120)
$ComputerList = $env:ComputerName
$Events = gc C:\Temp\ErrorCodes.txt
# Getting all event logs
Get-EventLog -AsString -ComputerName $Computername |
ForEach-Object {
# write status info
Write-Progress -Activity "Checking Eventlogs on \\$ComputerName" -Status $_
# get event entries and add the name of the log this came from
Get-EventLog -LogName $_ -EntryType Error, Warning -After $Start -ComputerName $ComputerName -ErrorAction SilentlyContinue |
Add-Member NoteProperty EventLog $_ -PassThru | Where-Object {$Events -contains $_.eventid}
} |
# sort descending
Sort-Object -Property EventLog |
# select the properties for the report
Select-Object EventLog, EventID, TimeGenerated, EntryType, Source, Message
# output into grid view window
Out-GridView -Title "All Errors & Warnings from \\$Computername"
Force it to be an array.. Otherwise it will come in as a string if there is only one item
$ComputerList = #(gc c:\folder\computerlist.txt)
PowerShell: How can I to force to get a result as an Array instead of Object
Related
I need to create a script in which will ask for a type of events to display (For example: system). The script will show on screen the events of the selected type grouped by the event id. These will be shown on the screen ordered by the number of events of the same.
I tried creating the script and these are my results. I would like to know if there is any mistake on it.
cls
$eventType = Read-host "Introduce one kind of event"
try { Get-EventLog -LogName $eventType | Group-Object 'InstanceID' | Sort-Object -Property InstanceID -Descending -ErrorAction Stop}
catch { Write-Output "unrecognizable event" }
I got your script to work by breaking the command for user input into its own variable.
$LogName = Read-host "Introduce one kind of event"
$eventType = try { Get-EventLog -LogName $LogName | Group-Object 'InstanceID' | Sort-Object -Property InstanceID -Descending -ErrorAction Stop} catch { Write-Output "unrecognizable event" }
$eventType
So after reading your code pre edit there is a couple of things that I would like to highlight;
1, You had pasted your code as a single line, this would have not executed as it would have considered everything else after cls as arguments. New lines and ; indicate end of command.
As a single line you would have to seperate your commands using ;
cls; $eventType = Read-host "Introduce one kind of event"; try { Get-EventLog -LogName $eventType | Group-Object 'InstanceID' | Sort-Object -Property InstanceID -Descending -ErrorAction Stop} catch { Write-Output "unrecognizable event" }
However I do advise breaking your code into multiple lines.
2, To order by the number of instances (ordered by the number of events of the same) you would need to modify your sort-object:
cls
$eventType = Read-host "Introduce one kind of event"
try { Get-EventLog -LogName $eventType | Group-Object 'InstanceID' | Sort-Object -Property Count -Descending -ErrorAction Stop}
catch { Write-Output "unrecognizable event" }
The initial object Get-EventLog is destroyed and replaced by the Group-Object object. The property you would then want to sort-object by is Count, you can inspect the properties of an object by using get-member.
I am creating a script to retrieve all the machine names from a .txt file then Query against them;
ComputerName
UserName (Of the last person to logon to the machine)
Date it was last Logged on to/Used
This is what i have
Clear-Host
$machines = Get-Content -Path C:\Users\khalifam\Desktop\Winver\MachineNames.txt
ForEach ($Compu in $machines) {
Get-WmiObject –ComputerName $machines –Class Win32_ComputerSystem | Select
Username, PSComputerName | FT
}
As sidenotes:
the hyphens for the parameter names are not hyphens, but En-Dashes, so I gather this code is copied from the internet somewhere
inside the loop you are using the wrong variable on the ComputerName parameter which should be $Compu
Having said that, I don't think you can get the info you need from the WMI Win32_ComputerSystem class..
What you will need to do is to parse the info from the computers eventlog:
# get an array of computernames loaded from the text file
$machines = Get-Content -Path C:\Users\khalifam\Desktop\Winver\MachineNames.txt
$result = foreach ($computer in $machines) {
# test if the compurer is on-line
if (!(Test-Connection -ComputerName $computer -Count 1 -Quiet)) {
Write-Warning "Computer '$computer' is off-line."
# skip this computer and carry on with the next iteration
continue
}
# search the computers eventlog and parse the username and last logon time from that
# you can play around with other values for -MaxEvents if you feel you're missing information.
Get-WinEvent -ComputerName $computer -FilterHashtable #{Logname='Security';ID=4672} -MaxEvents 20 |
Where-Object { $_.Properties[1].Value -notmatch 'SYSTEM|NETWORK SERVICE|LOCAL SERVICE' } |
Select-Object #{Name ='ComputerName'; Expression = {$_.MachineName}},
#{Name ='UserName'; Expression = {$_.Properties[1].Value}},
#{Name ='LastLogon'; Expression = {$_.TimeCreated}} -First 1
}
# show on screen:
$result | Format-Table -AutoSize
# save as CSV file
$result | Export-Csv -Path 'D:\LastLogonInfo.csv' -NoTypeInformation
Update
If I understand your comment correctly, you would like a list of all users (except for a few) and retrieve their latest login on a computer from the list.
In that case you can do the following:
# get an array of computernames loaded from the text file
$machines = Get-Content -Path C:\Users\khalifam\Desktop\Winver\MachineNames.txt
$result = foreach ($computer in $machines) {
# test if the compurer is on-line
if (!(Test-Connection -ComputerName $computer -Count 1 -Quiet)) {
Write-Warning "Computer '$computer' is off-line."
# skip this computer and carry on with the next iteration
continue
}
# you do not want to include these account logins
$exclude = '\$|SYSTEM|NETWORK SERVICE|LOCAL SERVICE|KHALIFAM'
# search the computers eventlog and parse the username and last logon time from that
# you can play around with other values for -MaxEvents if you feel you're missing information.
Get-WinEvent -ComputerName $computer -FilterHashtable #{Logname='Security';ID=4672} -MaxEvents 100 |
Where-Object { $_.Properties[1].Value -notmatch $exclude } |
Select-Object #{Name ='ComputerName'; Expression = {$_.MachineName}},
#{Name ='UserName'; Expression = {$_.Properties[1].Value}},
#{Name ='LastLogon'; Expression = {$_.TimeCreated}} |
Group-Object -Property UserName | ForEach-Object {
$_.Group | Sort-Object LastLogon -Descending | Select-Object -First 1
}
}
# show on screen:
$result | Format-Table -AutoSize
# save as CSV file
$result | Export-Csv -Path 'D:\LastLogonInfo.csv' -NoTypeInformation
I'm using the below code to pull the IP Address of the User (supplied at beginning of code) that had a failed logon attempt. The code works, but when I use GetType() the variable $ipp, it comes back as a Name is Object[] Base Type is System.Array I need this variable to be a string (I'm looking for the IP in a text file and removing it if it's found).
$ipp = Get-WinEvent -FilterHashtable #{LogName='Security';Id=4625;StartTime=$hours} |
Where-Object {$_.Properties[5].Value -like "*$userName*"} |
Select-Object -First 1 {$_.Properties[19].value}
I'm using PowerShell 5
Thanks
Kevin
Pre-warning: This will probably be your best bet for a full array of each bit of information from the bad attempt/lockout event. You can assign each object to a variable easily, check out the last line for some of the property names I use when checking locked accounts.
I have been doing a lot of this sort of stuff at work lately and came across a nice Microsoft demo. I unashamedly stole their script, works like a charm.
I hoped you were connecting to a domain controller but it looks like that event ID is for a bad attempt on the clients machine, not the DC.
Changed it a bit so you can slot it in after you have defined your $userName and left the Microsoft comments. Just check out line 87/88 as you may need to complete that if you encounter errors with your DC.
# Set up the lockout report
$report = #()
# Pick the DCs to crawl
$DCs = Get-ADDomainController -Filter * |
Select-Object HostName, IPv4Address, Site, OperatingSystem, OperationMasterRoles |
Out-Gridview -Title "Select the DCs to query" -PassThru |
Select-Object -ExpandProperty HostName
# Find the lockout stats for that user on all selected DCs
ForEach ($DC in $DCs) {
$report += Get-ADUser $userName -Server $DC -ErrorAction Continue `
-Properties cn, LockedOut, pwdLastSet, badPwdCount, badPasswordTime, lastLogon, lastLogoff, lastLogonTimeStamp, whenCreated, whenChanged | `
Select-Object *, #{name='DC';expression={$DC}}
}
$DCs = $report |
Select-Object `
DC, `
cn, `
LockedOut, `
pwdLastSet, `
#{name='pwdLastSetConverted';expression={[datetime]::fromFileTime($_.pwdlastset)}}, `
badPwdCount,
badPasswordTime, `
#{name='badPasswordTimeConverted';expression={[datetime]::fromFileTime($_.badPasswordTime)}}, `
lastLogon, `
#{name='lastLogonConverted';expression={[datetime]::fromFileTime($_.lastLogon)}}, `
lastLogoff, `
#{name='lastLogoffConverted';expression={[datetime]::fromFileTime($_.lastLogoff)}}, `
lastLogonTimeStamp, `
#{name='lastLogonTimestampConverted';expression={[datetime]::fromFileTime($_.lastLogonTimestamp)}}, `
whenCreated, `
whenChanged |
Out-GridView -Title "Select the DC to query event logs for lockouts" -PassThru
# Filter generated using Event Viewer GUI Custom View
# Logon/Lockout events in the last 24 hours
[xml]$xmlFilter = #"
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">*[System[(EventID=529 or EventID=644 or EventID=675 or EventID=676 or EventID=681 or EventID=4740 or EventID=4771) and TimeCreated[timediff(#SystemTime) <= 86400000]]]</Select>
</Query>
</QueryList>
"#
$Events = #()
ForEach ($DC in $DCs) {
"Getting events from $($DC.DC)"
# Must enable the firewall rule for remote EventLog management - CHECK WITH YOUR IT TEAM, THIS MAY BREACH YOUR COMPANY SECURITY POLICY
# Invoke-Command -ComputerName $DC.DC -ScriptBlock {Get-NetFirewallRule -Name *eventlog* | Where-Object {$_.Enabled -eq 'False'} | Enable-NetFirewallRule -Verbose}
### Filter for the userID in the event message properties
$Events += Get-WinEvent -ComputerName $DC.DC -FilterXML $xmlFilter
}
ForEach ($Event in $Events) {
# Convert the event to XML
$eventXML = [xml]$Event.ToXml()
# Iterate through each one of the XML message properties
For ($i=0; $i -lt $eventXML.Event.EventData.Data.Count; $i++) {
# Append these as object properties
Add-Member -InputObject $Event -MemberType NoteProperty -Force `
-Name $eventXML.Event.EventData.Data[$i].name `
-Value $eventXML.Event.EventData.Data[$i].'#text'
}
}
# View the lockout details
$Events | Where-Object {$_.TargetUserName -eq $userName} | Select-Object TargetUserName, IPAddress, MachineName, TimeCreated | Out-GridView
The PowerShell script below queries the Security event log on one or more servers for events with id 4663. When trying to retrieve all audit events for event id 4663 with the following code the computer throws the following exception: how can we to optimize this PowerShell?
So I just want to fetch security event log based on specific AD Users instead of all of users. Otherwise I want to retrieve what I need.
$server = "HOSTNAME"
$out = New-Object System.Text.StringBuilder
$out.AppendLine("ServerName,EventID,TimeCreated,UserName,File_or_Folder,AccessMask")
$ns = #{e = "http://schemas.microsoft.com/win/2004/08/events/event"}
foreach ($svr in $server)
{ $evts = Get-WinEvent -computer $svr -FilterHashtable #{logname="security";id="4663"} -oldest
foreach($evt in $evts)
{
$xml = [xml]$evt.ToXml()
$SubjectUserName = Select-Xml -Xml $xml -Namespace $ns -XPath "//e:Data[#Name='SubjectUserName']/text()" | Select-Object -ExpandProperty Node | Select-Object -ExpandProperty Value
$ObjectName = Select-Xml -Xml $xml -Namespace $ns -XPath "//e:Data[#Name='ObjectName']/text()" | Select-Object -ExpandProperty Node | Select-Object -ExpandProperty Value
$AccessMask = Select-Xml -Xml $xml -Namespace $ns -XPath "//e:Data[#Name='AccessMask']/text()" | Select-Object -ExpandProperty Node | Select-Object -ExpandProperty Value
$out.AppendLine("$($svr),$($evt.id),$($evt.TimeCreated),$SubjectUserName,$ObjectName,$AccessMask")
Write-Host $svr
Write-Host $evt.id,$evt.TimeCreated,$SubjectUserName,$ObjectName,$AccessMask
}
}
$out.ToString() | out-file -filepath C:\TEMP\4663Events.csv
Refactor the code so that the stringbuilder contents are flushed every now and then. This keeps its size more manageable. Like so,
$out = New-Object System.Text.StringBuilder
$out.AppendLine("ServerName,EventID,TimeCreated,UserName,File_or_Folder,AccessMask")
foreach($evt in $evts) {
$xml = [xml]$evt.ToXml()
...
$out.AppendLine("$($svr),$($evt.id),$($evt.TimeCreated),$SubjectUserName,$ObjectName,$AccessMask")
# If the stringbuffer is large enough, flush its contents to disk
# and start filling empty buffer again
if($out.length -ge 100MB) {
$out.ToString() | out-file -filepath C:\TEMP\4663Events.csv -append
$out.Clear()
}
}
# Remember to flush the buffer so that stuff that wasn't flushed in the
# foreach loop is saved as well
$out.ToString() | out-file -filepath C:\TEMP\4663Events.csv -append
Edit:
As the error is coming from Out-LineOutput, which is an internal cmdlet, it might be about the shell memory settings. You could try increasing the maximum memory per shell to, say 2 GB. Like so,
Set-Item .\MaxMemoryPerShellMB 2048
The MS Scripting Guys blog has a detailed article about configuring the limits
How can i add the server name at the left of each line result on this script?. Thank you!
$servers = Get-Content -path .\Machines.txt
[pscustomobject]$result = #()
$subresult =
ForEach ($server in $servers)
{
Set-Service -computername $servers -Name sacsvr -StartupType Disabled -PassThru
}
$result = $subresult
$result | Out-File local_group_members.csv
This is an example result:
Status Name DisplayName
------ ---- -----------
Stopped sacsvr Special Administration Console Helper
Stopped sacsvr Special Administration Console Helper
Stopped sacsvr Special Administration Console Helper
Alternatively you can just add a property to the objects you're outputting right now. Pipe your Set-Service to Add-Member like this:
Set-Service -computername $servers -Name sacsvr -StartupType Disabled -PassThru | Add-Member -MemberType NoteProperty -Name 'Server' -Value $Server -PassThru
Now each object that you pass to $subresult has a new property Server that is the name of the server it was run on. You'll probably want to pipe through Select when outputting to have the order you want.
$SubResult | Select Server, Status, Name, DisplayName | Export-CSV 'local_group_members.csv' -NoType
You can arbitrarily re-order or add to your output with Select-Object. You can use hash tables to include calculated properties such as your desired ServerName.
So for each server, you can set the services and tag the output with that server name:
ForEach ($server in $servers)
{
Set-Service -computername $server -Name sacsvr -StartupType Disabled -PassThru |
Select #{Name = 'ServerName'; Expression = {$server}}, Name, DisplayName, Status
}
The above is shorthand for:
Select-Object -Property (properties)
The -Property parameter allows you to select any arbitrary grouping of properties on the type of object being piped in. Another parameter, -InputObject allows us to pipe in objects by value.