Determine if an account is restricted to deny interactive login - powershell

Problem: Determine accounts with password does not expire across multiple environments, excluding accounts that can not be used to sign in interactively.
I am attempting to use powershell to generate a report that will show me account's who's passwords are set to never expire, however I want to exclude service accounts (accounts that have been restricted via GPO to only logon as service, similar process described in http://paulasitblog.blogspot.com/2017/01/deny-interactive-logon-for-service.html). I have found a few ways to pull this via powershell however it requires me to generate a list of servers, and run against accounts 1 at a time to see if they are restricted. Is there any switch that can be added to this that would be able to determine if an account has interactive logon disabled?
Current script I am using:
$b = $env:COMPUTERNAME
$c = Get-Date -Format "MM/dd/yyyy"
get-aduser -filter * -properties Name, PasswordNeverExpires |
where {$_.passwordNeverExpires -eq "true" } |
Select-Object DistinguishedName,Name,Enabled |
Export-csv Export-csv c:\Automation\$c-pw_never_expires-$b.csv -NoTypeInformation
The closest solutions I was able to find:
https://morgantechspace.com/2014/11/set-allow-log-on-locally-user-rights-via-powershell-cmd-csharp.html
Issue: This requires a 3rd party .dll, and I am unsure if this can be integrated to provide a single output.
https://www.powershellbros.com/get-user-rights-assignment-security-policy-settings/
This requires me to generate a server list, then run against the accounts to determine which accounts are limited.

Related

Powershell - Who activated a User

I'm a beginner in Powershell and I would like to create a script to check who activated a specific user in our AD.
So far, I have this:
Get-EventLog -LogName Security -ComputerName ad.root| Where-Object {$_.EventID -eq 4722} | Select-Object -Property *
First of all, is this right? It checks all the activated users in the ad.root domain.
Second...How can I search for a specific user a display it?
I tried the select-object parameter, but it don't work.
4722 is the right event to search for. But I advise to use get-winevent instead of get-eventlog. By doing so you have the far better filter options (xpath) and it is faster.
But first you must ensure that those events are being logged. In the GPO valid to Domain Controllers ensure that the following option is active:
Advanced Audit Policy Configuration -> Account Management -> Audit User Account Management = Success
Furthermore as Mathias already has pointed out you need to check the logs of all Domain Controllers. You can achieve this by forwarding the events to central store by using event log forwarding or by using a 3rd party product like splunk or elastic. But for sure you can also check for those events by only using PowerShell.
Back to your example, to filter the log for eventid 4722 for a specific user account by using get-eventlog:
$username = "user123"
get-eventlog -LogName security | ?{$_.eventid -eq 4722 -and $_.message -match $username}

Showing currently logged in user in a PowerShell running from a RMM Software as SYSTEM

i searched hours of my time and saw many ideas for this scenario but nothing worked for my like it should (i tested every code i saw on my own machine but nothing got me to the result i wanted.)
background: we are using a script in our RMM Software to Rename the Agents
$benutzer = [Environment]::UserName
Set-ItemProperty -Path "HKLM:\Software\MMSOFT Design\PC Monitor" -Name ComputerName -Value "$env:USERDOMAIN - $env:Computername - $benutzer"
This script gives us for the $env:USERNAME the user SYSTEM but we actually want the real USERNAME which is logged into this system.
Please help me out :)
The environment variable [System.Environment]::GetEnvironmentVariable('username') will give you the username for the executor of the script, in your case that is System because this is user who ran the code.
If you want to user the environment variable for the user, you must make it so the script been ran from or on behalf of the user, this also means that user must have "permissions" to modify the registry.
If I understand right, you need to know who is the "Logged in user" for the machine where that script runs, unfortunately there is nothing available from PowerShell that do that to my knowledge, instead you could use the build-in tool query for Windows machines, which will provide you with a list with all logged in users to that machine, you would need to further test it to get what you want from it, the output looks like this :
PS C:\Users\t-user> query user
USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME
>t-user console 1 Active none 8/29/2022 11:58 AM
The trick with query user is that it will provide you with the list of users in case more than one have logged in.
I see what you are trying to do, and here is a "dirty" example of doing it :
$loggedUserList= query user
if($loggedUserList.count -eq 2){
$user = $loggedUserList -split ">" -replace '\s\s+', ';' | convertfrom-csv -Delimiter ';' | select -ExpandProperty username
Write-Host "Logged in user is - $user"
}else{
Write-Host "More than one user have signed"
}

How to setup a group policy to set a logon script on every user in Active Directory using Powershell?

I know how to set group policy to add a logon script to every user using GUI but I wanted to know how can this be done using Powershell commands(or maybe with python).
Currently, the only real way to set a GPO setting via powershell requires that you know the registry key you're changing (all GPO settings resolve to registry entries), but be aware that settings done like this won't show up with the nice descriptions in the group policy gui tools:
Get-GPO -Name 'Logon Scripts' | Set-GPRegistryValue -Context User -Key 'HKEY_CURRENT_USER\path\to\key' -Value 'Foo.bat'
Generally, the better way to do what you want is to set the AD User's ScriptPath property instead:
Get-ADUser $user | Set-ADUser -ScriptPath 'Foo.bat'

Get user permissions to folder including indirect permissions through AD and local groups

I want to check whether a given Active Directory user (specified by username and domain) has read/(write) permissions on a given folder. And this unrelated to having them granted directly by user name or indirectly by some group membership. However I've been googling like 5 hours by now to no avail.
I understand, that Get-Acl Cmdlet is used to read folder permissions. Most likely the user is member of some group, that indirectly grants it permissions.
So my idea was to just match the output of
(Get-Acl <Folder>).Access | ft
against the group membership of the user.
I collect the group Information using the command
Get-ADPrincipalGroupMembership "<Username>" | select name
but found out, that this features an entirely different set of group names. I assumed, that the groups outputted by Get-Acl are local ones, while the other ones were AD-sided groups.
I found the command whoami /groups, that prints all groups, but only for the currently logged in user.
After quite some additional time I figured out the command (based on .NET):
(New-Object Security.Principal.WindowsIdentity -ArgumentList #(,"<User#fullDomain.com>")).Claims | select Value
This however just prints SIDs, while
(Get-Acl <Folder>).Access | ft
displays some human friendly output like "NT SERVICE\TrustedInstaller" and such.
I believe I'm pretty close, but I just can't get it to work.
On another note: Does this really have to be that complicated?
Other solutions I found only work based on direct user permissions but do not check group permissions.
Oh and one thing: Everything has to run on PowerShell 4.0 on Windows Server 2012 R2 and the PowerShell script will be running locally. No NuGet packages or anything requiring an Internet connection are allowed.

SID for Administrators group doesn't show in a member account

Now, before I start, I will let you in on a secret: this is on a Domain Controller.*
*The above statement is stricken due to irrelevance as the only significant change that occurs to the Local Administrator account and the Local Administrator Group (within the context and scope of this question) is minimal and doesn't alter the outcome enough to require differentiation.
I didn't have this kind of trouble on any of the other servers and I am willing to bet that the reason behind it is because it is on a DC.*
*Same reason as stated above. The accepted answer explains the inconsistency and was an oversight on my part, not the architecture (read features) of Windows Security or Domain Controllers.
I have been playing around with a few ideas on how to check if a script has been called from an account that is either the local Administrator or, at the very least, called by an account that is part of the Local Administrators group.
I have renamed the local Admin account, however, I know that I can see if the script has been called by local Admin account by typing:
(New-Object System.Security.Principal.NTAccount('reserved')).Translate([System.Security.Principal.SecurityIdentifier]).Value
and I can see if the SID ends in -500.
The problem occurs when I run a condition to see if the calling account is part of the Administrators group (which is a larger scope) by typing:
PS> [bool](([System.Security.Principal.WindowsIdentity]::GetCurrent()).Groups -match "S-1-5-32-544")
PS> False
A quick check to see what account it was using:
PS> $env:username
PS> reserved
or the needlessly complicated way (though I prefer it sometimes):
PS> Write-Host ((Get-WmiObject Win32_Account | ?{$_.SID.Substring($_.SID.Length-4,4) -eq '-500'}).Caption).Split("\",2)[1] -fore GREEN
PS> reserved
and I even type:
PS> net user reserved
where it tells me Local Group Memberships *Administrators.
I pull up ADUC (dsa.msc) and I look in the Builtin container and double-click on the Administrators group. I select the Members tag and lo, and behold, reserved is actually a member!
So, a recap:
By typing net user reserved, I was able to verify it was part of the Local Administrators group
I looked in ADUC and verified reserved was a member of the builtin Administrators group
I ensured reserved was indeed the Local Administrator account by verifying the SID started with S-1-5... and ended with ...-500
To take it a step further, I made sure the SID matched the Active Directory Group named "Administrators" by typing Get-ADGroup -Identity "Administrators". I then typed Get-ADGroupMember -Identity "Administrators" and made sure reserved was listed (it was AND the SID matched!).
When I check to see if the well-known Administrators Group SID is found in the Groups of that account (by getting the current Windows Identity), it says that it isn't.
What gives?
Why do I get every indication that it actually is a member of the Local Administrators group but that SID isn't found in the account's groups?
When a computer is promoted to a domain controller, there are no more local users or groups on the machine. Member computers have local users and groups, and can also use domain users and groups for authentication, but on a DC, there are only domain objects.
See also: https://serverfault.com/a/264327/236470
I happened to stumble across something and I realized the answer to this question. For the sake of those that come here looking for assistance, here is the answer to my question:
Very simply--in regards to Powershell--if the Administrator Group SID (S-1-5-32-544) does not show up in the Groups of the user, that is a first-line indication that the script is not running with Administrative credentials.
For example, when I type out:
([Security.Principal.WindowsIdentity]::GetCurrent()).Groups
and I do not see the Administrator Group SID listed even though I know for a fact that the account I am signed into is a member of the Administrator Group, it means the current Powershell process does not have Administrative credentials.
If you click Run As Administrator and type the same as above, you will see that it lists the Administrator Group SID in Groups.
The reason why I was experiencing the inconsistency is simply because I was not running the Powershell process as an Administrator.
So, in short, there are a few ways you can check to verify if your current Powershell session has Administrator credentials. The first one is found in countless websites around the internet and is very common (I did not write this one):
$myWindowsID = [Security.Principal.WindowsIdentity]::GetCurrent()
$myWindowsPrincipal = New-Object Security.Principal.WindowsPrincipal($myWindowsID)
$adminRole = [Security.Principal.WindowsBuiltInRole]::Administrator
if($myWindowsPrincipal.IsInRole($adminRole)) {
\\ TODO: Process is running as Administrator
Clear-Host
} else {
$newProcess = New-Object System.Diagnostics.ProcessStartInfo "Powershell"
$newProcess.Arguments = "& '" + $script:MyInvocation.MyCommand.Path + "'"
$newProcess.Verb = "runas"
[System.Diagnostics.Process]::Start($newProcess)
exit
}
Here is another way (I did write this one):
[Security.Principal.WindowsIdentity]::GetCurrent() | %{
if($_.Groups -contains "S-1-5-32-544") {
\\ TODO: Process is running as Administrator
Clear-Host
} else {
Start Powershell -ArgumentList "& '$MyInvocation.MyCommand.Path'" -Verb runas
exit
}
}
# The Foreach-Object (%) could be replaced with another pipeline filter
I see a lot of people asking this question and because of Powershell appealing to many Systems Administrator (especially ones without a background in programming), I really think this will come in handy for others down the line.