PowerShell script is triggering the AD alert when executing on any local server. as user or computer

Copper Contributor

Hello All,

 

I have PowerShell script which generates the data from each local server. This script tested and its working fine but the challenge is it trigger the alert on AD server as  "user of computer logged on to this computer from the network"  , but script is executing on any server not on AD. Why this is happening I am not able to find out it. Is the AD level security configured or hardening which is creating this problem.

Where I do find the exact cause of this. Can any one help me please. 

I am attaching the script here for the reference.

############################Script#####################

$Computer = $env:ComputerName
$OutputDir = "c:\temp\"
$Name = ($OutputDir + $Computer + "_LocalUser.csv")
out-file -filepath $Name
$OutputFile = $Name
Add-Content -Path $OutPutFile -Value "ComputerName;OS;IP;UserID;FullName;SID;UserType;PasswordLastSet;Enabled;UserMayChangePassword;PasswordNeverExpires;InteractiveLogon;AccessDetails;LastLogOn;TimeZone"
$LocalUsers = Get-WmiObject -Class Win32_UserAccount -Filter "LocalAccount=True" | Select-Object -ExpandProperty Name

$localgroups = Get-WmiObject Win32_Group -Filter “LocalAccount=True” | Select-Object -ExpandProperty Name

$groupsOutput = $null

$IP = $(((ipconfig | findstr [0-9].\.)[0]).Split()[-1])

if($PSVersionTable.PSVersion.Major -gt 4){
foreach($localuser in $LocalUsers) {
$Name = $localuser
$FullName = Get-LocalUser -Name $localuser | Select-Object -ExpandProperty FullName
$SID = Get-LocalUser -Name $localuser | Select-Object -ExpandProperty SID
$UserType = Get-LocalUser -Name $localuser | Select-Object -ExpandProperty PrincipalSource

$PasswordLastSet = Get-LocalUser -Name $localuser | Select-Object -ExpandProperty PasswordLastSet
$Enabled = Get-LocalUser -Name $localuser | Select-Object -ExpandProperty Enabled
$UserMayChangePassword = Get-LocalUser -Name $localuser | Select-Object -ExpandProperty UserMayChangePassword
$PasswordNeverExpires = (Get-LocalUser -Name $localuser | Select-Object -ExpandProperty PasswordExpires) -eq $null

[Int]$i=0

$groupsOutput = ""

$groups = (Get-LocalGroup | Where-Object { (Get-LocalGroupMember $_).name -eq "$Computer\$Name" }).Name


foreach($group in $groups) {
$i++


if($i -le 1)
{
$groupsOutput = -join ("$groupsOutput", "$group")
}
else
{
$groupsOutput = -join ("$groupsOutput", " / " ,"$group")
}

}


$LastLogOn = Get-LocalUser -Name $localuser | Select-Object -ExpandProperty LastLogOn
$TimeZone = [regex]::Matches([System.TimeZoneInfo]::Local.DisplayName, '(?<=\()(.*)(?=\))').Value
Add-Content -Path $OutPutFile -Value "$Computer;Windows;$IP;$Name;$FullName;$SID;$UserType;$PasswordLastSet;$Enabled;$UserMayChangePassword;$PasswordNeverExpires;;$groupsOutput;$LastLogOn;$TimeZone"
}
}else{
foreach($localuser in $LocalUsers) {
$user = Get-WmiObject -query "SELECT * FROM Win32_UserAccount WHERE LocalAccount = 'True' and Name = ""$localuser"""
$Name = $localuser
$FullName = $user.FullName
$SID = $user.SID
$UserType = "Local"
$PasswordLastSet = $(net user $Name| findstr /B /C:"Password last set")
$PasswordLastSet = $PasswordLastSet.Substring(29)
$Enabled = -not $user.Disabled
$UserMayChangePassword = -not $user.PasswordChangeable
$PasswordNeverExpires = -not $user.PasswordExpires
$groupList = Get-CimInstance -ClassName Win32_UserAccount -Filter "Name='$name'" | Get-CimAssociatedInstance -Association Win32_GroupUser | Select-Object Name
$groups = ""
foreach($group in $groupList.Name){
$groups += $group + ","
}
$groups = $groups.Substring(0,$groups.Length-1)
$LastLogOn = $(net user $Name| findstr /B /C:"Last logon")
$LastLogOn = $LastLogOn.Substring(29)
$TimeZone = [regex]::Matches([System.TimeZoneInfo]::Local.DisplayName, '(?<=\()(.*)(?=\))').Value
$passwordNeverExpires = -not $user.passwordExpires
Add-Content -Path $OutPutFile -Value "$Computer;Windows;$IP;$Name;$FullName;$SID;$UserType;$PasswordLastSet;$Enabled;$UserMayChangePassword;$PasswordNeverExpires;;$groups;$LastLogOn;$TimeZone"

}
}

 

12 Replies
The get-local user/group cmdlet is only for servers, computers locally or joined to an Active Directory domain. The cmdlet doesn't work on a Active Directory Domain Controller because it has no local users/groups but Active Directory users and groups. (You should use get-aduser / get-adgroup for that)

@Harm_Veenstra One thing I also understood that, The user who is executing the script is the local user not domain user. Its trying to collect the details from the target server but in backend some where its connecting to AD Server. And the error I am getting is like below. User and the error type. 

 

Sumitsk_0-1652072069955.png

Sumitsk_1-1652072413693.png

Is the server level hardening to block the login or in the script which is trying to do get something from AD server instead of Target servers where the actual script is executing.

 

@Sumitsk 

 

My expectation is that the NTLM event is coming from how the script is being called, not from the script itself.

 

Rather than focusing on the script content, focus on how it's being run, i.e. via something like psexec, Invoke-Command, a scheduled task, SCCM utility, etc., etc.

 

In theory, WMI can also be the source but the calls to Get-WmiObject and Get-CimInstance do not use such triggers (such as alternate credentials and/or impersonation levels) meaning that is irrelevant in this case. That only leaves how it's being launched.

 

While the script itself is not written very well, there's nothing in it that would trigger the events you're seeing.

 

Cheers,

Lain

Yes Lain, We are using the BMC TrueSight Server Automation tool which push the script in 100 target servers in any directory and execute it on all 100 servers, After that Security team raise the concern like they have high volume alert which was around 4956 alerts.

@Sumitsk 

 

It sounds like you can stop looking into the script and switch your focus onto engaging with the BMC instead.

 

You could perform a quick cross-check beforehand by distributing a much simpler one line script (below) via BMC TrueSight, in which case if you deploy it the exact same way as your original script above, I'd wager you'll see the exact same NTLM event reported by your security team.

 

Write-Host "Hello world!"

 

If it does indeed trigger the NTLM event then at least you can be sure the configuration issue lies within TrueSight.

 

The authentication package used can very much be chosen by the launcher (BMC TrueSight in this case) and it appears it's chosen NTLM.

 

One thought - and this is only a guess - is that within your TrueSight configuration, see if you can specify the "run as" account in RFC822 format - more simply known as e-mail format.

 

So, for example, if you specified the account within the TrueSight package in NT4 format like:

 

mydomain\myLaunchAccount

 

Then try the RFC822 format of:

 

myLaunchAccount@mydomain.com

 

It may or may not make a difference but I have seen software use NTLM when the NT4 format is used and Kerberos (which is what your security team probably wants you to use) when RFC822-style is used. And it should be a reasonably quick to test, so I'd give that a go before reaching out to BMC.

 

Cheers,

Lain

Thanks Lain for your clarification. I have tested this without any tool on servers manually, same alert triggered and security team reported it again. With the help of BMC also checked but it was coming to the script and user. If manual execution is triggering the alert then might be something at firewall rule or user level permission or server hardening. I also don't any see commands which are creating a issue here.

@Sumitsk 

 

I'm not quite understanding what you tested manually. Do you mean you ran the script manually on the server - i.e. as a PS1 file - and it generated an NTLM event?

 

If so, were you running the PS1 as yourself or the TrueSight action account?

 

You might also want to look at the following two policies and configure them for auditing (if they're not already configured). I'd be looking to configure them locally on:

 

 

You can then runs some commands from the PowerShell console and see the impact in the event log at "Applications and Services Log\Microsoft\Windows\NTLM\Operational".

 

You can use a domain group policy to do this, but if neither policy is already set, then I'd simply use the local group policy editor during the testing phase (gpedit.msc) as it's easier/quicker to undo once testing is complete.

 

Read more about NTLM auditing policies here: NTLM Blocking and You: Application Analysis and Auditing Methodologies in Windows 7 - Microsoft Tech....

 

As an aside, the Windows Firewall won't feature in this in any way, shape or form - if that's the firewall you were referring to. It has zero per cent to do with authentication packages unless you're using Connection Security Rules, which I'd safely wager you're not using (and they're IPsec-based anyway, putting NTLM a long way out of reach.)

 

I'm also not familiar with any policy that forcibly degrades Kerberos to NTLM, so I wouldn't suspect hardening. Misconfiguration of something, maybe, but not hardening.

 

Cheers,

Lain

@Sumitsk 

 

Reflecting on Ned's article (linked above) - he's such a good writer! - make sure BMC TrueSight is connecting to these servers by name and not IP address.

 

Connecting via IP address precludes the use of Kerberos, meaning NTLM is the only option.

 

It's so easy to forget basic requirements like this one.

 

Cheers,

Lain

Script manually on the server - i.e. as a PS1 file - and it generated an NTLM event?
Yes manually executed the same script in the PowerShell console with my user id on one server. Which triggered the alert. I am referring your given article to know more about it.
Hello Lain,
First I need to solve without tool or without using the tool user login, Then I will go for the tool.
I am checking myself in one server with PowerShell. Also checking the things which you have mentioned.

Thanks Lain

@Sumitsk 

 

I just ran a quick test of your first WMI statement and checked the NTLM/Operational log, and it does actually generate an NTLM audit event.

 

This is the relevant line:

 

 

Get-WmiObject -Class Win32_UserAccount -Filter "LocalAccount=True"

 

 

Edited: Just to add the second Win32_UserAccount statement also throws an audit result, so it seems to be something specific to querying the Win32_UserAccount instances, despite the filter being for local accounts.

 

Get-WmiObject -query "SELECT * FROM Win32_UserAccount WHERE LocalAccount = 'True' and Name = ""$localuser"""

 

The Win32_Group query does not trip the NTLM audit.

 

Cheers,

Lain

@Sumitsk 

 

Here's a really, really quick re-write that doesn't trip the NTLM audit.

 

It uses the positively ancient ADSI WinNT provider, which takes me back to my late NT4/early Windows 2000 days, so a real blast from the past.

 

One "advantage" though is you don't need to have two code paths as you currently do to cater to different PowerShell versions as this will work on 5.1 and earlier just fine.

 

Personally, I'd write the script quite differently but I wanted to keep as much of your old one as possible while resolving the WMI oddity.

 

Give it a go and tweak what you need to, to get it to do what you need.

 

 

$Computer = $env:ComputerName
$OutputDir = "c:\temp\"
$Name = ($OutputDir + $Computer + "_LocalUser.csv")
out-file -filepath $Name
$OutputFile = $Name
Add-Content -Path $OutPutFile -Value "ComputerName;OS;IP;UserID;FullName;SID;UserType;PasswordLastSet;Enabled;UserMayChangePassword;PasswordNeverExpires;InteractiveLogon;AccessDetails;LastLogOn;TimeZone"
$LocalUsers = ([adsi]"WinNT://$($env:COMPUTERNAME),Computer").Children | Where-Object { $_.SchemaClassName -eq "User" };

$localgroups = ([adsi]"WinNT://$($env:COMPUTERNAME),Computer").Children | Where-Object { $_.SchemaClassName -eq "Group" };

$IP = (Get-NetIPAddress -PrefixOrigin Dhcp, Manual | Select-Object -Property IPAddress).IPAddress -join ", "

foreach($localuser in $LocalUsers)
{
    $NameParts = $localuser.Path.Split("/");
    $Name = $NameParts[-1];
    $FullName = "$($NameParts[-2])\$($NameParts[-1])";
    $SID = [System.Security.Principal.SecurityIdentifier]::new($localuser.objectSid[0], 0).Value;
    $UserType = "Local";

    $PasswordLastSet = [datetime]::Now.AddSeconds($localuser.PasswordAge.Value * -1);
    $Enabled = ($localuser.UserFlags.Value -band 0x2) -eq 0;
    $UserMayChangePassword = ($localuser.UserFlags.Value -band 0x40) -eq 0;
    $PasswordNeverExpires = ($localuser.UserFlags.Value -band 0x10000) -ne 0;

    $groupsOutput = ($localgroups | Where-Object { $_.IsMember($localuser.Path) }).Name -join " / ";

    $LastLogOn = if ($localuser.Properties.Contains("LastLogin")) { $localuser.LastLogin.Value.ToString("u"); } else { "never"; };
    $TimeZone = [regex]::Matches([System.TimeZoneInfo]::Local.DisplayName, '(?<=\()(.*)(?=\))').Value
    Add-Content -Path $OutPutFile -Value "$Computer;Windows;$IP;$Name;$FullName;$SID;$UserType;$PasswordLastSet;$Enabled;$UserMayChangePassword;$PasswordNeverExpires;;$groupsOutput;$LastLogOn;$TimeZone"
}

 

 

Cheers,

Lain