Skip to content

Instantly share code, notes, and snippets.

@laymanstake
Created August 24, 2023 17:02
Show Gist options
  • Save laymanstake/9c9cc965a6712cea6851b305a02d06f2 to your computer and use it in GitHub Desktop.
Save laymanstake/9c9cc965a6712cea6851b305a02d06f2 to your computer and use it in GitHub Desktop.
Function Start-SecurityCheck {
[CmdletBinding()]
Param(
[Parameter(ValueFromPipeline = $true, mandatory = $true)]$DomainName,
[Parameter(ValueFromPipeline = $true, mandatory = $true)][pscredential]$Credential
)
$SecuritySettings = @()
$DCs = (Get-ADDomainController -Filter * -Server $DomainName -Credential $Credential).hostname
$PDC = (Test-Connection -Computername (Get-ADDomainController -Filter * -Server $DomainName -Credential $Credential).Hostname -count 1 -AsJob | Get-Job | Receive-Job -Wait | Where-Object { $null -ne $_.Responsetime } | sort-object Responsetime | select-Object Address -first 1).Address
$null = Get-Job | Remove-Job
ForEach ($DC in $DCs) {
if (Test-Connection -ComputerName $Dc -Count 4 -Quiet) {
try {
$remotereg = ([Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $DC))
$results = (
$remotereg.OpenSubKey('System\CurrentControlSet\Control\Lsa').GetValue('LmCompatibilityLevel'),
$remotereg.OpenSubKey('System\CurrentControlSet\Control\Lsa').GetValue('NoLMHash'),
$remotereg.OpenSubKey('System\CurrentControlSet\Control\Lsa').GetValue('RestrictAnonymous'),
$remotereg.OpenSubKey('System\CurrentControlSet\Services\NTDS\Parameters').GetValue('LDAPServerIntegrity'),
$remotereg.OpenSubKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System').GetValue('InactivityTimeoutSecs'),
$remotereg.OpenSubKey('SOFTWARE\Microsoft\Windows\NetworkProvider\HardenedPaths').GetValueNames()
)
$null = $remotereg.Close()
}
catch {
Write-Log -logtext "Could not check for security related registry keys on domain controller $dc : $($_.Exception.Message)" -logpath $logpath
$results = ("", "", "", "", "", "")
}
if ($results) {
$NTLM = switch ($results[0]) {
5 { "Send NTLMv2 response only. Refuse LM & NTLM" }
4 { "Send NTLMv2 response only. Refuse LM" }
3 { "Send NTLMv2 response only" }
2 { "Send NTLM response only" }
1 { "Send LM & NTLM - use NTLMv2 session security if negotiated" }
0 { "Send LM & NTLM responses" }
Default {
switch ((Get-ADCOmputer ($dc).split(".")[0] -Properties operatingsystem -Server $PDC).operatingsystem ) {
{ $_ -like "*2022*" -OR $_ -like "*2019*" -OR $_ -like "*2016*" -OR $_ -like "*2012 R2*" } { "Send NTLMv2 response only. Refuse LM & NTLM" }
Default { "Not configured, OS default assumed" }
}
}
}
$LMHash = switch ($results[1]) {
1 { "Enabled" }
0 { "Disabled" }
Default { "Not configured" }
}
$RestrictAnnon = switch ($results[2]) {
0 { "Disabled" }
1 { "Enabled" }
Default { "Not configured" }
}
$LDAPIntegrity = switch ($results[3]) {
0 { "Does not requires signing" }
1 { "Requires signing" }
Default { "Not configured" }
}
$InactivityTimeout = switch ( $results[4] ) {
{ $_ -le 900 -AND $_ -ne 0 -AND $_ -ne $null } { "900 or fewer second(s), but not 0: $($_)" }
{ $_ -eq 0 } { "0 second" }
{ $_ -gt 900 } { "More than 900 seconds: $($_) seconds" }
Default {
switch ((Get-ADCOmputer ($dc).split(".")[0] -Properties operatingsystem -Server $PDC).operatingsystem ) {
{ $_ -like "*2022*" -OR $_ -like "*2019*" -OR $_ -like "*2016*" -OR $_ -like "*2012*" } { "OS default: 900 second" }
Default { "Unlimited" }
}
}
}
$SYSVOLHardened = switch (($results[5] -like "*SYSVOL*") -like "*") {
$true { "True" }
$false { "False" }
Default { "False" }
}
$NetlogonHardened = switch (($results[5] -like "*Netlogon*") -like "*") {
$true { "True" }
$false { "False" }
Default { "False" }
}
$settings = ($NTLM, $LMHash, $RestrictAnnon, $LDAPIntegrity, $InactivityTimeout, $SYSVOLHardened, $NetlogonHardened)
}
else {
$settings = ("Access denied", "Access denied", "Access denied", "Access denied", "Access denied", "Access denied", "Access denied")
Write-Log -logtext "Could not check for security related security settings on domain controller $dc as regisitry not accessible : $($_.exception.message)" -logpath $logpath
}
if (Test-WSMan -ComputerName $DC -ErrorAction SilentlyContinue) {
try {
$settings += invoke-command -ComputerName $DC -Credential $Credential -ScriptBlock {
$null = secedit.exe /export /areas USER_RIGHTS /cfg "$env:TEMP\secedit.cfg"
$seceditContent = Get-Content "$env:TEMP\secedit.cfg"
$LocalLogonSIDs = ((($seceditContent | Select-String "SeInteractiveLogonRight") -split "=")[1] -replace "\*", "" -replace " ", "") -split ","
try {
$LocalLogonUsers = $LocalLogonSIDs | Where-Object { $_ -ne "" } | ForEach-Object {
if ($_ -like "S-1*") {
$SID = New-Object System.Security.Principal.SecurityIdentifier($_)
$User = $SID.Translate([System.Security.Principal.NTAccount])
$User.Value
}
else { $_ } }
}
catch {}
$LocalLogonUsers -join "`n"
$RemoteLogonSIDs = ((($seceditContent | Select-String "SeRemoteInteractiveLogonRight") -split "=")[1] -replace "\*", "" -replace " ", "") -split ","
try {
$RemoteLogonUsers = $RemoteLogonSIDs | Where-Object { $_ -ne "" } | ForEach-Object {
if ($_ -like "S-1*") {
$SID = New-Object System.Security.Principal.SecurityIdentifier($_)
$User = $SID.Translate([System.Security.Principal.NTAccount])
$User.Value
}
else { $_ } }
}
catch {}
$RemoteLogonUsers -join "`n"
$DenyNetworkLogonSIDs = ((($seceditContent | Select-String "SeDenyNetworkLogonRight") -split "=")[1] -replace "\*", "" -replace " ", "") -split ","
try {
$DenyNetworkLogonUsers = $DenyNetworkLogonSIDs | Where-Object { $_ -ne "" } | ForEach-Object {
if ($_ -like "S-1*") {
$SID = New-Object System.Security.Principal.SecurityIdentifier($_)
$User = $SID.Translate([System.Security.Principal.NTAccount])
$User.Value
}
else { $_ } }
}
catch {}
$DenyNetworkLogonUsers -join "`n"
$DenyServiceLogonSIDs = ((($seceditContent | Select-String "SeDenyServiceLogonRight") -split "=")[1] -replace "\*", "" -replace " ", "") -split ","
try {
$DenyServiceLogonUsers = $DenyServiceLogonSIDs | Where-Object { $_ -ne "" } | ForEach-Object {
if ($_ -like "S-1*") {
$SID = New-Object System.Security.Principal.SecurityIdentifier($_)
$User = $SID.Translate([System.Security.Principal.NTAccount])
$User.Value
}
else { $_ } }
}
catch {}
$DenyServiceLogonUsers -join "`n"
$DenyBatchLogonSIDs = ((($seceditContent | Select-String "SeDenyBatchLogonRight") -split "=")[1] -replace "\*", "" -replace " ", "") -split ","
try {
$DenyBatchLogonUsers = $DenyBatchLogonSIDs | Where-Object { $_ -ne "" } | ForEach-Object {
if ($_ -like "S-1*") {
$SID = New-Object System.Security.Principal.SecurityIdentifier($_)
$User = $SID.Translate([System.Security.Principal.NTAccount])
$User.Value
}
else { $_ } }
}
catch {}
$DenyBatchLogonUsers -join "`n"
$DenyInteractiveLogonSIDs = ((($seceditContent | Select-String "SeDenyInteractiveLogonRight") -split "=")[1] -replace "\*", "" -replace " ", "") -split ","
try {
$DenyInteractiveLogonUsers = $DenyInteractiveLogonSIDs | Where-Object { $_ -ne "" } | ForEach-Object {
if ($_ -like "S-1*") {
$SID = New-Object System.Security.Principal.SecurityIdentifier($_)
$User = $SID.Translate([System.Security.Principal.NTAccount])
$User.Value
}
else { $_ } }
}
catch {}
$DenyInteractiveLogonUsers -join "`n"
$null = Remove-Item "$env:TEMP\secedit.cfg"
}
}
catch {
$settings += ("Access denied", "Access denied", "Access denied", "Access denied", "Access denied", "Access denied")
Write-Log -logtext "Could not check for secedit related security settings on domain controller $dc : $($_.Exception.Message)" -logpath $logpath
}
}
else {
$settings += ("Access denied", "Access denied", "Access denied", "Access denied", "Access denied", "Access denied")
Write-Log -logtext "Could not check for security related security settings on domain controller $dc as PS remoting not available : $($_.exception.message)" -logpath $logpath
}
$SecuritySettings += [PSCustomObject]@{
DomainName = $DomainName
DCName = $DC
"Network security: LAN Manager authentication level" = $settings[0]
"Network security: Do not store LAN Manager hash value on next password change" = $settings[1]
"Network access: Allow anonymous SID/Name translation" = $settings[2]
"Domain controller: LDAP server signing requirements" = $settings[3]
"Interactive logon: Machine inactivity limit" = $settings[4]
"UNC Path SYSVOL hardened?" = $settings[5]
"UNC Path NETLGON hardened?" = $settings[6]
"Allow logon locally on domain controllers" = $settings[7]
"Allow logon through Terminal Services on domain controllers" = $settings[8]
"Deny access to this computer from the network" = $settings[9]
"Deny log on as a service" = $settings[10]
"Deny log on as a batch job" = $settings[11]
"Deny Interactive logon" = $settings[12]
}
}
else {
$SecuritySettings += [PSCustomObject]@{
DomainName = $DomainName
DCName = $DC
"Network security: LAN Manager authentication level" = "DC is down"
"Network security: Do not store LAN Manager hash value on next password change" = "DC is down"
"Network access: Allow anonymous SID/Name translation" = "DC is down"
"Domain controller: LDAP server signing requirements" = "DC is down"
"Interactive logon: Machine inactivity limit" = "DC is down"
"UNC Path SYSVOL hardened?" = "DC is down"
"UNC Path NETLGON hardened?" = "DC is down"
"Allow logon locally on domain controllers" = "DC is down"
"Allow logon through Terminal Services on domain controllers" = "DC is down"
"Deny access to this computer from the network" = "DC is down"
"Deny log on as a service" = "DC is down"
"Deny log on as a batch job" = "DC is down"
"Deny Interactive logon" = "DC is down"
}
Write-Log -logtext "Could not check for security related security settings on domain controller $dc as DC is down." -logpath $logpath
}
$message = "Working over domain: $DomainName Domain Controller $DC security checks."
New-BaloonNotification -title "Information" -message $message
Write-Log -logtext $message -logpath $logpath
}
return $SecuritySettings
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment