Security Group changes - Task - powershell

I'm currently auditing security events 4728 and 4729 via powershell in order to check group policy changes in a specific domain controller.
The main idea is to check anomalies between a default AD group policy(a "given configuration", for the company group) and the one that changed(from the new snapshot) at the end of the week.
How could I spot differences beetween these two outputs?
I'd use Get-WinEvent -LogName Security, but we can discuss it.
For Changes I refer to these https://learn.microsoft.com/en-us/windows/security/threat-protection/auditing/audit-security-group-management
(4728,4729 for instance)
I'm looking for a situation like this: an administrator add a user to a security group because the latter has to access a specific file for a short period of time.
Then the admin somehow forgets to restore the original user's configuration policy.
This generates an anomaly, considering the default AD Group Policy.
I have to spot this change from the output.
Now I've wrapped up my rudimentary explination, is there anything you can think of to help with my problem?
Thanks in advance

The basic command you're looking for would be like this:
$StartDate = (Get-Date).AddDays(-1)
Get-WinEvent -FilterHashtable #{ LogName='Security'; Id=4728, 4729; StartTime=$StartDate }
In a script it would be something like this:
$StartDate = (Get-Date).AddDays(-1)
$Results = Get-WinEvent -FilterHashtable #{ LogName='Security'; Id=4728, 4729; StartTime=$StartDate }
if ( $Results )
{
# Send e-mail or something here
}
If you want more complex queries you might format it differently.
$DaysInThePast = 1
$Hash = #{
LogName = 'Security'
Id = 4728, 4729
StartTime = (Get-Date).AddDays(-$DaysInThePast)
}
Get-WinEvent -FilterHashtable $Hash

Related

Powershell: How to pull Event Viewer message and time

I am trying to pull users out of the logoff events within security.
Using the below code I can pull the usernames but I am not sure how to modify it to pull the time from the event log as well?
Many thanks
$events = get-eventlog -logname Security -instanceid 4634 -Newest 5
foreach ($ev in $events) {
$me = $ev.Message -match "(Account Name:).*"
if ($me) {
$matches[0]
}
}
I'm not exactly sure what you are attempting to do. However, Get-EventLog is deprecated in favor of Get-WinEvent which is faster and has much better filtering options, and example may look something like this:
$FilterHash = #{
LogName = 'Security'
Id = 4624
}
Get-WinEvent -FilterHashtable $FilterHash -MaxEvents 5 |
ForEach-Object{
If($_.Properties[1].Value -eq $me) {
Write-Host "Account Name : ($_.Properties[1].Value)"
}
}
The -FilterHashtable parameter is the most popular, but there are also -FilterXPath and -FilterXML params you can look at in the documentation.
Important: In my case, I didn't have 4634 events. The property value and array position can be determined by looking at the XML view of a given log entry in Event Viewer. Just look under then and count the array indices from 0.
Another way to do that is to just isolate a single entry and echo the properties to the screen, and again just count to get the right index number. This is important because different info may be in different positions in different events etc.
Get-WinEvent is really robust. I strongly recommend taking a look at the documentation!

retrieve computer names admin account logged on through AD

How would retrieve computer names and their IP addresses in Active Directory which are logged into by an admin account?
I can retrieve local admin accounts with my script below:
function get-localadministrators {
param ([string]$computername=$env:computername)
$computername = $computername.toupper()
$ADMINS = get-wmiobject -computername $computername -query "select * from win32_groupuser where GroupComponent=""Win32_Group.Domain='$computername',Name='administrators'""" | % {$_.partcomponent}
foreach ($ADMIN in $ADMINS) {
$admin = $admin.replace("$computernamerootcimv2:Win32_UserAccount.Domain=","") # trims the results for a user
$admin = $admin.replace("$computernamerootcimv2:Win32_Group.Domain=","") # trims the results for a group
$admin = $admin.replace('",Name="',"")
$admin = $admin.REPLACE("""","")#strips the last "
$objOutput = New-Object PSObject -Property #{
Machinename = $computername
Fullname = ($admin)
DomainName =$admin.split("")[0]
UserName = $admin.split("")[1]
}#end object
$objreport+=#($objoutput)
}#end for
return $objreport
}#end function
but what I want is to return all instances of Administrator logged on to Computers. Is this possible or is there anything that would return similar results?
You are not going to be able to do this with AD alone.
How many computers are we talking here? Nevertheless, i would make use of the eventlog. Each logon-event is stored and has the SID of the user that logs on (or triggers the event). Event 7001 (logon) is what you are looking for.
You could retrieve these events in een XML format. This XML contains the SID of the user that has triggered the event. You can either use a .NET translation function to convert it into a SamAccountName OR you can just retrieve all SID's from AD and compare them that way (so maybe make use of a hasbtable).
I have written a script some time ago that uses a lot of these techniques.
It was meant to see when a user has logged on and off AND locked and unlocked their computer. You can find a blog-post about it here:
https://cookiecrumbles.github.io/GetLogonEventViewer/
That blogpost also references the github where you can find the script i made.
With some tweaking, you could make it into a tool that you need.

Setting a DateTime to $null/empty using PowerShell and the SCSM cmdlets

I'm currently trying to sync additional attributes from the AD (Active Directory) for user objects in SCSM (System Center Service Manager) using a PowerShell script.
The extension I wrote for this, includes an attribute for the expiration date of a AD user account (DateTime value, named DateTimeAttribute in the example) if the user account doesn't expire it should be empty/null.
Using Import-SCSMInstance, which should be similar to a CSV import, it kind of works by passing "null" for the field. The problem is that Import-SCSMInstance seems to be quite unreliable and it doesn't offer any kind of information of why it works or doesn't work. Using Update-SCSMClassInstance seems to work a lot better but I can't figure out a way to clear the field using this and even using [DateTime]::MinValue will result in an error, stating that it's an invalid value.
So would anyone have an idea on how to clear the value using Update-SCSMClassInstance or figure out why Import-SCSMInstance might or might not work?
A simple example for this could look like the following:
$server = "<ServerName>"
$extensionGuid = "<GUID>"
Import-Module 'C:\Program Files\System Center 2012 R2\Service Manager\Powershell\System.Center.Service.Manager.psd1'
New-SCManagementGroupConnection -ComputerName $server
$extensionClass = Get-SCSMClass -Id $extensionGuid
$scsmUserObject = Get-SCSMClassInstance -Class $extensionClass -Filter 'UserName -eq "<User>"'
# Error
$scsmUserObject.DateTimeAttribute = ""
# Works but fails on Update-SCSMClassInstance
$scsmUserObject.DateTimeAttribute = $null
$scsmUserObject.DateTimeAttribute = [DateTime]::MinValue
# Works
$scsmUserObject.DateTimeAttribute = "01-01-1970"
Update-SCSMClassInstance -Instance $scsmUserObject
It seems that you can't clear a date once it's filled. When you write $null, it sets the date to 1-1-0001 01:00:00, which is an invalid date causing the update-scsmclassinstance to fail.
What we have set as a user's AD property when we don't want something to expire, is 2999-12-31 (yyyy-MM-dd). Perhaps this could help, although it's not directly what you asked for...
Also, you can use the pipeline to update a property in SCSM:
Get-SCSMClassInstance -Class $extensionClass -Filter 'UserName -eq "<User>"' | % {$_.DateTimeAttribute = <date>; $_} | update-scsmclassinstance
It doesn't look like it's currently possible to clear custom date attributes using the PowerShell cmdlets.

returning and referencing remote powershell variable results

I'm very new to powershell so looking some assistance. I am trying to run remote powershell script to check health of or VDI enviroment using Citrix Commandlets. (I am implementing the script on Microsoft orchestrator .Net Activity). So I have the following code:
#2012 VDI Desktop check
$vdims = "MyCitrixPowershellSDKServer"
function vdidesktopcheck
{
asnp Citrix*
$result = Get-BrokerDesktop -InMaintenanceMode $True -DesktopGroupName Unidesk
$result
}
$output = invoke-command -computer $vdims -scriptblock ${function:vdidesktopcheck}
$machinename = $output.machinename
$machinename
$state = $output.RegistrationState
$state
So when I use orchestrator to expose the variables $machinename, $state - I get the 'last' result from the involked Get-BrokerDesktop query. However Get-Brokerdesktop query may have multiple machines returned so I am hoping to be able to reference each of the machines that match the query output. Thats the basic requirement - what I am hoping to be able to do is further refine the basic Get-BrokerDesktop query to be able to count the number on machines output to say > 3 (ie more than 3 machines in MaintMode is unacceptable) and also check that the MachineName property is not equal to a particular value, ie the 3 test machine names in the environment which may be expected to be in MaintenanceMode.
Hope this makes sense, if not I'll try and elaborate. Any help much appreciated!!
One of the limitations of Orchestrator is that you can only pass strings across the data bus, and you need to pass an array of objects. You need to serialize the object array to a string. One way to do that is to convert the array to json, then use convertfrom-json when you get it back to get an object array to work with.
Don't have a SCORCH server handy to test with, so this isn't tested at all.
$vdims = "MyCitrixPowershellSDKServer"
function vdidesktopcheck
{
asnp Citrix*
$result = Get-BrokerDesktop -InMaintenanceMode $True -DesktopGroupName Unidesk
$result
}
$output = invoke-command -computer $vdims -scriptblock ${function:vdidesktopcheck} |
select machinename,RegistrationState | ConvertTo-Json
$Output

Powershell -get-eventdata

I am trying to create a script that pulls failed log on attempts for certain events in the past 24 hours but I cant figure out how to pull the account information out. User is Null all the time so info is blank BUT when I look in the general tab I can see "Account Information".
I would like to pull and add what it shows in the XML view under "event data" which is TargetUserName. How can I get this done? What I have so far works fine but I need the username info and what my script pulls is always blank.
System - windows server 2008 R2
Log I am pulling from is security log with event ID's 4625,4768,4771,4772 for the past 24 hours.
My code:
get-eventlog Security 4625,4768,4771,4772 -after ((get-date).addDays(-1))| export-csv
I think you'll have to change this around because each event has different messages, but if I try to fail a login, I can get the username from event 4776 like this:
# Get the most recent event 4776
$event = Get-EventLog -LogName Security -InstanceId 4776 -newest 1
# Pull the "Logon Account: testuser" text from the event log message
$usernameMatch = $event.Message -match 'Logon Account:\s+(?<account>.*)'
# Use the magic variable $matches which gets created by -match
if ($usernameMatch) {
write-output "Someone tried to logon as the user $matches['account']"
}
Otherwise, I think you can get the XML message using this:
$event = Get-WinEvent -FilterHashtable #{id=4776} -LogName Security -maxevent 1
$event.ToXML()
#Peter-core appears to know how to accomplish this without needing to parse and search the message body and without converting to XML.
Use the following to find that the extended fields (part of template?) for each event:
(Get-WinEvent -ListProvider Microsoft-Windows-Security-Auditing).Events|Where-object{#(4625,4768,4771,4772) -contains $_.Id}
Use get-winevent to get the events, you can use xpath to filter data more quick (only return events you are interested in to start with), or you can filter them after they return using where-object. Xpath is better option for larger number of devices, eventlogs, or events, but I hate trying to write one.
Get-WinEvent -log Security|Where-object{$_.TimeCreated -gt ((get-date).addDays(-1)) -and #(4625,4768,4771,4772) -contains $_.Id}
From there you can try and implemnt what #Peter-Core wrote. I can't make it work for myself, but the coding looks sound.