diff --git a/windows/powershell/dnscheck.ps1 b/windows/powershell/dnscheck.ps1 new file mode 100644 index 0000000..163e617 --- /dev/null +++ b/windows/powershell/dnscheck.ps1 @@ -0,0 +1,135 @@ +param ( + # Domain name being checked + [Parameter(Mandatory = $false)] + [string]$Name, + + # These 2 are only for listing + [Parameter(Mandatory = $false)] + [string]$DnsServer, + + [switch]$List +) + +# Usage was done by AI but its so cool +function Show-Usage { + Write-Host "`nUsage:" -ForegroundColor Yellow + Write-Host " .\$(Split-Path -Leaf $PSCommandPath) -Name [-List] [-DnsServer ]" -ForegroundColor White + Write-Host "`nParameters:" -ForegroundColor Yellow + Write-Host " -Name Domain name to resolve or check." -ForegroundColor White + Write-Host " -List List all records for the given domain (requires -DnsServer)." -ForegroundColor White + Write-Host " -DnsServer Target DNS server for listing." -ForegroundColor White + Write-Host "`nExamples:" -ForegroundColor Yellow + Write-Host " Check DNS servers and resolve a name:" -ForegroundColor White + Write-Host " .\dnscheck.ps1 -Name example.com" -ForegroundColor DarkGray + Write-Host " List records from a specific DNS server:" -ForegroundColor White + Write-Host " .\dnscheck.ps1 -Name example.com -List -DnsServer 192.168.1.1" -ForegroundColor DarkGray + Write-Host "" +} + +# Show usage if parameters are invalid +if ($List -and -not $DnsServer) { + Write-Error "You must specify -DnsServer when using -List." + Show-Usage + exit 1 +} + +if (-not $Name) { + Write-Error "Missing required parameter: -Name." + Show-Usage + exit 1 +} + + +# Function returns all of the records on a given DNS server. Only run when List is true +function Show-Records { + param( + [string]$Target, + [string]$Zone + ) + + try { + $records = dnscmd $Target /enumrecords $Zone '@' 2>&1 + # since dnscmd is a cmd utility and not a cmdlet, error handling was a bit weird. This should work + if ($LASTEXITCODE -ne 0) { + throw "Failed to enumerate records from $Target" + } + # Returns the string value of dnscommand + $records + } + catch { + Write-Error "Error retrieving DNS records: $_" + } +} + + +function Test-Servers { + $dnsInfo = Get-DnsClientServerAddress | # Grabs all DNS servers for each interface + Where-Object { $_.AddressFamily -eq 2 } | # Only ones with ipv4 addresses + Select-Object InterfaceAlias, ServerAddresses # Selects both the interface its on, and the IP of the dns server + + foreach ($entry in $dnsInfo) { + if (-not $entry.ServerAddresses -or $entry.ServerAddresses.Count -eq 0) { # if the entry is either null or 0, skip it. This does happen, as if the record is only ipv6 then it will still grab it unfortunatly + continue # Continue is neat- it skips the current loop but doesnt break and moves on to the next item + } + + + # if you are struggling to read the next 2 lines, its nested arrays. + Write-Host "`nInterface: $($entry.InterfaceAlias)" -ForegroundColor Cyan + foreach ($server in $entry.ServerAddresses) { + Write-Host -NoNewline "Checking DNS server: $server... " + # Test-NetConnection returns a bool when Informationlevel is set to Quiet. very neat! + if (Test-NetConnection -ComputerName $server -Port 53 -InformationLevel Quiet -ErrorAction SilentlyContinue) { + Write-Host "Port 53 Reachable and accepting." -ForegroundColor Green + } + else { + # Actually a great error check. This step *can* be slow, but it will give an overview of if it can connect to the host VIA ICMP, what its route was, etc etc. + Write-Host "ICMP Check Failed. Target may be unreachable, or Port 53 may be closed" -ForegroundColor Red + Test-NetConnection -ComputerName $server -TraceRoute -informationlevel detailed + } + } + } +} + +function Resolve-Dns { + param( + [string]$QueryName + ) + + try { + # prints out the responding DNS server, along with its address + $nsResult = nslookup $QueryName 2>&1 | Where-Object { $_ -match '^(Server:|Address:)' } + if ($nsResult) { + Write-Host "`nNSLookup Results:" -ForegroundColor Yellow + $nsResult + } + else { + Write-Warning "No nslookup results. Check to see if computer is on fire and/or someone ran chatgpt powershell" + } + + # Resolve-DnsName + Write-Host "`nResolve-DnsName Results:" -ForegroundColor Yellow + Resolve-DnsName -Name $QueryName -ErrorAction Stop # throws if an error occurs. Otherwise prints all of the records associated with the query + } + catch { + Write-Host "DNS resolution failed." -ForegroundColor Red + Write-Warning $_.Exception.Message + } +} + +# --- Main --- + +if ($List) { + if (-not $DnsServer) { + Write-Error "You must specify a target DNS server with -DnsServer when using -List." + exit 1 + } + Show-Records -Target $DnsServer -Zone $Name +} +else { + Test-Servers + Resolve-Dns -QueryName $Name +} + + + + diff --git a/windows/powershell/ldapcheck.ps1 b/windows/powershell/ldapcheck.ps1 index e69de29..21af213 100644 --- a/windows/powershell/ldapcheck.ps1 +++ b/windows/powershell/ldapcheck.ps1 @@ -0,0 +1,49 @@ +# Script still in testing phase. Idea behind it is very cool, but complexity is high, and I want to be able to document it well + +# Prompt user for input +# Hard code domain prior to running in comp + +# Will add the ability to pass in parameters later, but for now I need to run more testing first +$domain = Read-Host "Enter domain (example.com)" +$username = Read-Host "Enter username" +$password = Read-Host "Enter password" -AsSecureString +# Prevents the password from being displayed in plain text in the console. This makes the script messier, but more secure. +# When marshal is used to convert the secure string to a plain text string, it will expose the password in memory. This is not ideal +# Solution to the memory problem given by AI: + #$ptr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($password) + #$plainPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto($ptr) + +# Zero out and free the unmanaged memory (important for security) + #[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ptr) +# Requires more testing to see if this is trustworthy or neccesary + + +# Convert secure string to plain text for LDAP use +# Marshal is a NET class used to convert between managed and unmanaged code (In this case, raw memory) +# Second half turns the secure string into a BSTR (Binary String), and then returns a pointer to that BSTR (This is the piece that exposes the password in memory) +# The pointer is then converted to a plain string using the PtrToStringAuto +$plainPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto( + [Runtime.InteropServices.Marshal]::SecureStringToBSTR($password) +) + +# Construct the LDAP path and credentials +$ldapPath = "LDAP://$domain" +$userPrincipal = "$domain\$username" + +try { + # Create the DirectoryEntry object with credentials + # This does not create an object in the directory, it creates a local object that represents the LDAP path and credentials you want to use to access it + $entry = New-Object System.DirectoryServices.DirectoryEntry($ldapPath, $userPrincipal, $plainPassword) + + # Attempt to access a property to trigger the bind + # This takes the path and credentials you provided before, and attempts to bind to the LDAP server using those credentials + # This seems like a really weird and specific way to do this, but stackoverflow said it was a good idea, and I cant see any reason why it wouldnt wory or be insecure. + $native = $entry.NativeObject + + Write-Host "LDAP authentication successful." +} +catch { + Write-Host "LDAP connection to $domain as $username failed with error:" -ForegroundColor Red + Write-Host $_.Exception.GetType().FullName "`n" -ForegroundColor Red + Write-Host $_.Exception.Message -ForegroundColor Red +}