commit bf6f94384fdd99aecd55a6bd5a58bbe215e33624 Author: Zak Bearman Date: Wed Sep 24 14:50:06 2025 +1200 new push diff --git a/Asteroid.ps1 b/Asteroid.ps1 new file mode 100644 index 0000000..4b11aa9 --- /dev/null +++ b/Asteroid.ps1 @@ -0,0 +1,76 @@ +Function Start-AdfsServerTrace { + param ( + [string]$ActivityId, + [switch]$IncludeDebug, + [string[]]$ComputerName + ) + + $jobs = @() + foreach ($computer in $ComputerName) { + $jobs += Start-Job -ScriptBlock { + param ($ActivityId, $IncludeDebug, $computer) + + $logNames = @("Security", "Application", "System") + if ($IncludeDebug) { $logNames += "AD FS Tracing/Debug" } + + $events = @() + foreach ($log in $logNames) { + try { + $events += Get-WinEvent -ComputerName $computer -LogName $log -ErrorAction SilentlyContinue | + Where-Object { $_.ActivityId -eq $ActivityId } + } catch { + Write-Error "Failed to retrieve events from $computer for log $log" + } + } + + return [PSCustomObject]@{ + ComputerName = $computer + Events = $events + } + } -ArgumentList $ActivityId, $IncludeDebug, $computer + } + + return $jobs +} + +Function Receive-AdfsServerTrace { + param ( + [Parameter(Mandatory = $true)] + [System.Management.Automation.Job[]]$Jobs + ) + + $results = @() + foreach ($job in $Jobs) { + $jobResult = Receive-Job -Job $job -Wait -AutoRemoveJob + $results += $jobResult + } + + return $results +} + +Function Get-AdfsServerTrace { + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string]$ActivityId, + + [switch]$IncludeDebug, + + [string]$OutHtmlFilePath, + + [string[]]$ComputerName = @("localhost") + ) + + # Start jobs to search all computers in parallel and retrieve results + $jobs = Start-AdfsServerTrace -ActivityId $ActivityId -IncludeDebug:$IncludeDebug -ComputerName $ComputerName + $results = Receive-AdfsServerTrace -Jobs $jobs + + if ($OutHtmlFilePath) { + $results | ConvertTo-Html -Property ComputerName, Events | Out-File $OutHtmlFilePath -Force + Write-Output "Report Generated at $OutHtmlFilePath" + Start-Process $OutHtmlFilePath + } else { + Write-Output $results + } +} diff --git a/Binoculars.ps1 b/Binoculars.ps1 new file mode 100644 index 0000000..dfdad58 --- /dev/null +++ b/Binoculars.ps1 @@ -0,0 +1,51 @@ +## Created by Zak Bearman - Intel - Datacom - For use on any domain that WinRM is enabled and supported for remote log searching## +cls +# Define the username you are searching for +$username = read-host "Please enter users account" # Replace with the username of the locked-out user +# Get the PDC Emulator +$pdcemulator = (Get-ADDomain).PDCEmulator +$DomainControllers = Get-ADDomainController $pdcemulator | Select-Object -ExpandProperty HostName + +# Define log file path +$logFile = "C:\Temp\AccountLockoutLog.txt" + +# Create the log file if it doesn't exist +if (-not (Test-Path $logFile)) { + New-Item -Path $logFile -ItemType File -Force +} + +# Loop indefinitely every 5 minutes +while ($true) { + foreach ($DC in $DomainControllers) { + Write-Host "Searching on: $DC" + Add-Content -Path $logFile -Value "Searching on: $DC - $(Get-Date)" + + # Use Invoke-Command to remotely query the domain controller + Invoke-Command -ComputerName $DC -ScriptBlock { + param ($username) + + # Query the Security event log for Event ID 4625 (Failed Login Attempt) + $events4625 = Get-EventLog -LogName "Security" -InstanceId 4625 -Newest 1000 | Where-Object { $_.Message -like "*$username*" } + foreach ($event in $events4625) { + $timeGenerated = $event.TimeGenerated + $message = $event.Message + + Write-Host "Failed login attempt: $message at $timeGenerated" + Add-Content -Path $using:logFile -Value "Failed login attempt: $message at $timeGenerated" + } + + # Query the Security event log for Event ID 4740 (Account Lockout) + $events4740 = Get-EventLog -LogName "Security" -InstanceId 4740 -Newest 1000 | Where-Object { $_.Message -like "*$username*" } + foreach ($event in $events4740) { + $timeGenerated = $event.TimeGenerated + $message = $event.Message + + Write-Host "Account locked out: $message at $timeGenerated" + Add-Content -Path $using:logFile -Value "Account locked out: $message at $timeGenerated" + } + } -ArgumentList $username + } + + # Wait for 10 seconds (10 seconds) + Start-Sleep -Seconds 10 +} diff --git a/Cartographer.ps1 b/Cartographer.ps1 new file mode 100644 index 0000000..b60be46 --- /dev/null +++ b/Cartographer.ps1 @@ -0,0 +1,317 @@ +# Cartographer - DNS Record Mapping Tool with GUI - Map - IP to DNS record based on subnet +# Import required assemblies for GUI +Add-Type -AssemblyName System.Windows.Forms +Add-Type -AssemblyName System.Drawing + +# Convert IP addresses to integers for comparison +function Convert-IPToInt { + param ( + [string]$IPAddress + ) + [array]$octets = $IPAddress.Split('.') + return [int]($octets[0]) * 16777216 + [int]($octets[1]) * 65536 + [int]($octets[2]) * 256 + [int]($octets[3]) +} + +# Convert integer back to IP address +function Convert-IntToIP { + param ( + [int64]$Integer + ) + $octet1 = [Math]::Floor($Integer / 16777216) + $remainder = $Integer % 16777216 + $octet2 = [Math]::Floor($remainder / 65536) + $remainder = $remainder % 65536 + $octet3 = [Math]::Floor($remainder / 256) + $octet4 = $remainder % 256 + return "$octet1.$octet2.$octet3.$octet4" +} + +# Get subnet range based on IP and mask +function Get-SubnetRange { + param ( + [string]$IPAddress + ) + + # Assuming /24 subnet + $octets = $IPAddress.Split('.') + $networkPrefix = "$($octets[0]).$($octets[1]).$($octets[2])" + $rangeStart = "$networkPrefix.1" + $rangeEnd = "$networkPrefix.254" + + return @{ + Start = $rangeStart + End = $rangeEnd + } +} + +# Get available DNS servers +function Get-AvailableDnsServers { +# $dnsServers = @("localhost") + + $clientDnsServers = Get-DnsClientServerAddress | + Where-Object { $_.ServerAddresses -ne $null } | + ForEach-Object { + $_.ServerAddresses | Where-Object { $_ -match '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$' } + } | + Select-Object -Unique + + $dnsServers += $clientDnsServers + + # Try to add domain controllers if we're in a domain environment + try { + $domainControllers = Get-ADDomainController -Filter * | + ForEach-Object { $_.HostName } + $dnsServers += $domainControllers + } catch { + # Not in a domain environment or AD module not available, continue without it + } + + return $dnsServers | Select-Object -Unique +} + +# Query DNS for records +function Search-DnsRecords { + param ( + [string]$DnsServer, + [string]$IPRangeStart, + [string]$IPRangeEnd + ) + + $StartInt = Convert-IPToInt $IPRangeStart + $EndInt = Convert-IPToInt $IPRangeEnd + + $Results = @() + + try { + $Zones = Get-DnsServerZone -ComputerName $DnsServer -ErrorAction Stop + + foreach ($Zone in $Zones) { + $Records = Get-DnsServerResourceRecord -ZoneName $Zone.ZoneName -ComputerName $DnsServer -ErrorAction SilentlyContinue + foreach ($Record in $Records) { + if ($Record.RecordType -eq "A") { + $IPInt = Convert-IPToInt $Record.RecordData.IPv4Address.ToString() + if ($IPInt -ge $StartInt -and $IPInt -le $EndInt) { + $Results += [PSCustomObject]@{ + IPAddress = $Record.RecordData.IPv4Address + Hostname = $Record.HostName + Zone = $Zone.ZoneName + } + } + } + } + } + } catch { + [System.Windows.Forms.MessageBox]::Show("Error querying DNS server: $_", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error) + } + + return $Results +} + +# Create the main form +$form = New-Object System.Windows.Forms.Form +$form.Text = "Cartographer - DNS Record Mapping Tool" +$form.Size = New-Object System.Drawing.Size(800, 600) +$form.StartPosition = "CenterScreen" +$form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedDialog +$form.MaximizeBox = $false + +# DNS Server selection +$dnsServerLabel = New-Object System.Windows.Forms.Label +$dnsServerLabel.Text = "DNS Server:" +$dnsServerLabel.Location = New-Object System.Drawing.Point(20, 20) +$dnsServerLabel.Size = New-Object System.Drawing.Size(100, 20) +$form.Controls.Add($dnsServerLabel) + +$dnsServerComboBox = New-Object System.Windows.Forms.ComboBox +$dnsServerComboBox.Location = New-Object System.Drawing.Point(130, 20) +$dnsServerComboBox.Size = New-Object System.Drawing.Size(200, 20) +$dnsServerComboBox.DropDownStyle = [System.Windows.Forms.ComboBoxStyle]::DropDownList +$form.Controls.Add($dnsServerComboBox) + +# Populate DNS Server dropdown +$dnsServers = Get-AvailableDnsServers +foreach ($server in $dnsServers) { + $dnsServerComboBox.Items.Add($server) +} +if ($dnsServerComboBox.Items.Count -gt 0) { + $dnsServerComboBox.SelectedIndex = 0 +} + +# IP Range Selection Group +$ipRangeGroupBox = New-Object System.Windows.Forms.GroupBox +$ipRangeGroupBox.Text = "IP Range Selection" +$ipRangeGroupBox.Location = New-Object System.Drawing.Point(20, 50) +$ipRangeGroupBox.Size = New-Object System.Drawing.Size(750, 120) +$form.Controls.Add($ipRangeGroupBox) + +# Radio buttons for range selection +$subnetRadioButton = New-Object System.Windows.Forms.RadioButton +$subnetRadioButton.Text = "Scan Full /24 Subnet" +$subnetRadioButton.Location = New-Object System.Drawing.Point(20, 20) +$subnetRadioButton.Size = New-Object System.Drawing.Size(150, 20) +$subnetRadioButton.Checked = $true +$ipRangeGroupBox.Controls.Add($subnetRadioButton) + +$customRangeRadioButton = New-Object System.Windows.Forms.RadioButton +$customRangeRadioButton.Text = "Custom IP Range" +$customRangeRadioButton.Location = New-Object System.Drawing.Point(20, 50) +$customRangeRadioButton.Size = New-Object System.Drawing.Size(150, 20) +$ipRangeGroupBox.Controls.Add($customRangeRadioButton) + +# Subnet IP entry +$subnetIPLabel = New-Object System.Windows.Forms.Label +$subnetIPLabel.Text = "Subnet IP Address:" +$subnetIPLabel.Location = New-Object System.Drawing.Point(180, 20) +$subnetIPLabel.Size = New-Object System.Drawing.Size(120, 20) +$ipRangeGroupBox.Controls.Add($subnetIPLabel) + +$subnetIPTextBox = New-Object System.Windows.Forms.TextBox +$subnetIPTextBox.Location = New-Object System.Drawing.Point(300, 20) +$subnetIPTextBox.Size = New-Object System.Drawing.Size(150, 20) +$subnetIPTextBox.Text = "192.168.1.1" +$ipRangeGroupBox.Controls.Add($subnetIPTextBox) + +# Custom range IP entries +$startIPLabel = New-Object System.Windows.Forms.Label +$startIPLabel.Text = "Start IP Address:" +$startIPLabel.Location = New-Object System.Drawing.Point(180, 50) +$startIPLabel.Size = New-Object System.Drawing.Size(120, 20) +$ipRangeGroupBox.Controls.Add($startIPLabel) + +$startIPTextBox = New-Object System.Windows.Forms.TextBox +$startIPTextBox.Location = New-Object System.Drawing.Point(300, 50) +$startIPTextBox.Size = New-Object System.Drawing.Size(150, 20) +$startIPTextBox.Text = "192.168.1.1" +$startIPTextBox.Enabled = $false +$ipRangeGroupBox.Controls.Add($startIPTextBox) + +$endIPLabel = New-Object System.Windows.Forms.Label +$endIPLabel.Text = "End IP Address:" +$endIPLabel.Location = New-Object System.Drawing.Point(460, 50) +$endIPLabel.Size = New-Object System.Drawing.Size(120, 20) +$ipRangeGroupBox.Controls.Add($endIPLabel) + +$endIPTextBox = New-Object System.Windows.Forms.TextBox +$endIPTextBox.Location = New-Object System.Drawing.Point(580, 50) +$endIPTextBox.Size = New-Object System.Drawing.Size(150, 20) +$endIPTextBox.Text = "192.168.1.254" +$endIPTextBox.Enabled = $false +$ipRangeGroupBox.Controls.Add($endIPTextBox) + +# Radio button event handlers +$subnetRadioButton.Add_CheckedChanged({ + if ($subnetRadioButton.Checked) { + $subnetIPTextBox.Enabled = $true + $startIPTextBox.Enabled = $false + $endIPTextBox.Enabled = $false + } +}) + +$customRangeRadioButton.Add_CheckedChanged({ + if ($customRangeRadioButton.Checked) { + $subnetIPTextBox.Enabled = $false + $startIPTextBox.Enabled = $true + $endIPTextBox.Enabled = $true + } +}) + +# Auto-calculate subnet range from subnet IP +$subnetIPTextBox.Add_TextChanged({ + if ($subnetRadioButton.Checked -and $subnetIPTextBox.Text -match '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$') { + $range = Get-SubnetRange -IPAddress $subnetIPTextBox.Text + $startIPTextBox.Text = $range.Start + $endIPTextBox.Text = $range.End + } +}) + +# Search Button +$searchButton = New-Object System.Windows.Forms.Button +$searchButton.Text = "Search DNS Records" +$searchButton.Location = New-Object System.Drawing.Point(20, 180) +$searchButton.Size = New-Object System.Drawing.Size(150, 30) +$form.Controls.Add($searchButton) + +# Status Label +$statusLabel = New-Object System.Windows.Forms.Label +$statusLabel.Text = "Ready" +$statusLabel.Location = New-Object System.Drawing.Point(180, 185) +$statusLabel.Size = New-Object System.Drawing.Size(590, 20) +$form.Controls.Add($statusLabel) + +# Results DataGridView +$resultsDataGridView = New-Object System.Windows.Forms.DataGridView +$resultsDataGridView.Location = New-Object System.Drawing.Point(20, 220) +$resultsDataGridView.Size = New-Object System.Drawing.Size(750, 300) +$resultsDataGridView.AutoSizeColumnsMode = [System.Windows.Forms.DataGridViewAutoSizeColumnsMode]::Fill +$resultsDataGridView.AllowUserToAddRows = $false +$resultsDataGridView.AllowUserToDeleteRows = $false +$resultsDataGridView.ReadOnly = $true +$resultsDataGridView.MultiSelect = $false +$resultsDataGridView.SelectionMode = [System.Windows.Forms.DataGridViewSelectionMode]::FullRowSelect +$form.Controls.Add($resultsDataGridView) + +# Export Button +$exportButton = New-Object System.Windows.Forms.Button +$exportButton.Text = "Export Results" +$exportButton.Location = New-Object System.Drawing.Point(20, 530) +$exportButton.Size = New-Object System.Drawing.Size(120, 30) +$exportButton.Enabled = $false +$form.Controls.Add($exportButton) + +# Search button click event +$searchButton.Add_Click({ + $statusLabel.Text = "Searching DNS records..." + $resultsDataGridView.DataSource = $null + $exportButton.Enabled = $false + + $selectedDnsServer = $dnsServerComboBox.SelectedItem.ToString() + + $ipRangeStart = "" + $ipRangeEnd = "" + + if ($subnetRadioButton.Checked) { + $range = Get-SubnetRange -IPAddress $subnetIPTextBox.Text + $ipRangeStart = $range.Start + $ipRangeEnd = $range.End + } else { + $ipRangeStart = $startIPTextBox.Text + $ipRangeEnd = $endIPTextBox.Text + } + + $results = Search-DnsRecords -DnsServer $selectedDnsServer -IPRangeStart $ipRangeStart -IPRangeEnd $ipRangeEnd + + if ($results.Count -gt 0) { + $dataTable = New-Object System.Data.DataTable + $dataTable.Columns.Add("IPAddress", [string]) + $dataTable.Columns.Add("Hostname", [string]) + $dataTable.Columns.Add("Zone", [string]) + + foreach ($result in $results) { + $dataTable.Rows.Add($result.IPAddress.ToString(), $result.Hostname, $result.Zone) + } + + $resultsDataGridView.DataSource = $dataTable + $statusLabel.Text = "Found $($results.Count) DNS records" + $exportButton.Enabled = $true + } else { + $statusLabel.Text = "No DNS records found in the specified range" + } +}) + +# Export button click event +$exportButton.Add_Click({ + $saveFileDialog = New-Object System.Windows.Forms.SaveFileDialog + $saveFileDialog.Filter = "CSV Files (*.csv)|*.csv|All Files (*.*)|*.*" + $saveFileDialog.Title = "Export DNS Records" + $saveFileDialog.FileName = "DNSRecords_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv" + + if ($saveFileDialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { + $dataTable = $resultsDataGridView.DataSource + $dataTable | Export-Csv -Path $saveFileDialog.FileName -NoTypeInformation + $statusLabel.Text = "Exported to $($saveFileDialog.FileName)" + } +}) + +# Show the form +[void]$form.ShowDialog() + diff --git a/Contrast.ps1 b/Contrast.ps1 new file mode 100644 index 0000000..2a4f970 --- /dev/null +++ b/Contrast.ps1 @@ -0,0 +1,203 @@ +Add-Type -AssemblyName System.Windows.Forms + +#Set Domain Controller Variable + +$domaincontroller = "fqdn.domain.placeholder" ##################### UPDATE THIS LINE ##################### + +# Create a form +$form = New-Object Windows.Forms.Form +$form.Text = "Compare AD Group Memberships" +$form.Width = 600 +$form.Height = 900 +$form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedSingle + +# Signature for UPNs +$labelSignature = New-Object Windows.Forms.Label +$labelSignature.Text = "Made by Zak Bearman - Intel" +$labelSignature.Location = New-Object Drawing.Point(10, 832) +$form.Controls.Add($labelSignature) + +# Labels and Textboxes for UPNs +$labelPrimaryUser = New-Object Windows.Forms.Label +$labelPrimaryUser.Text = "Primary User UPN:" +$labelPrimaryUser.Location = New-Object Drawing.Point(10, 23) +$form.Controls.Add($labelPrimaryUser) + +$textBoxPrimaryUser = New-Object Windows.Forms.TextBox +$textBoxPrimaryUser.Location = New-Object Drawing.Point(120, 20) +$textBoxPrimaryUser.Width = 200 +$form.Controls.Add($textBoxPrimaryUser) + +# ComboBox for selecting the number of users to compare against +$labelNumUsers = New-Object Windows.Forms.Label +$labelNumUsers.Text = "How many other users?" +$labelNumUsers.Location = New-Object Drawing.Point(10, 50) +$form.Controls.Add($labelNumUsers) + +$comboBoxNumUsers = New-Object Windows.Forms.ComboBox +$comboBoxNumUsers.Location = New-Object Drawing.Point(250, 50) +$comboBoxNumUsers.DropDownStyle = [System.Windows.Forms.ComboBoxStyle]::DropDownList +$comboBoxNumUsers.Items.Add("1") +$comboBoxNumUsers.Items.Add("2") +$comboBoxNumUsers.Items.Add("3") +$comboBoxNumUsers.SelectedIndex = 0 +$form.Controls.Add($comboBoxNumUsers) + +# GroupBox for UPNs of users to compare against +$groupBoxUsers = New-Object Windows.Forms.GroupBox +$groupBoxUsers.Text = "Users to Compare Against:" +$groupBoxUsers.Location = New-Object Drawing.Point(10, 80) +$groupBoxUsers.Width = 340 +$groupBoxUsers.Height = 100 +$form.Controls.Add($groupBoxUsers) + +# Textboxes for entering UPNs based on the selected number of users +$textBoxUser1 = New-Object Windows.Forms.TextBox +$textBoxUser1.Location = New-Object Drawing.Point(10, 20) +$textBoxUser1.Width = 200 +$groupBoxUsers.Controls.Add($textBoxUser1) + +$textBoxUser2 = New-Object Windows.Forms.TextBox +$textBoxUser2.Location = New-Object Drawing.Point(10, 50) +$textBoxUser2.Width = 200 +$textBoxUser2.Visible = $false +$groupBoxUsers.Controls.Add($textBoxUser2) + +$textBoxUser3 = New-Object Windows.Forms.TextBox +$textBoxUser3.Location = New-Object Drawing.Point(10, 80) +$textBoxUser3.Width = 200 +$textBoxUser3.Visible = $false +$groupBoxUsers.Controls.Add($textBoxUser3) + +# Button to initiate comparison +$buttonCompare = New-Object Windows.Forms.Button +$buttonCompare.Text = "Compare" +$buttonCompare.Location = New-Object Drawing.Point(120, 195) +$form.Controls.Add($buttonCompare) + +# Help button to display usage instructions +$buttonHelp = New-Object Windows.Forms.Button +$buttonHelp.Text = "Click Me" +$buttonHelp.Location = New-Object Drawing.Point(215, 195) +$form.Controls.Add($buttonHelp) + +# Scrollable and selectable textbox for displaying output +$textBoxOutput = New-Object Windows.Forms.TextBox +$textBoxOutput.Location = New-Object Drawing.Point(10, 230) +$textBoxOutput.Width = 560 +$textBoxOutput.Height = 600 +$textBoxOutput.Multiline = $true +$textBoxOutput.ScrollBars = "Vertical" +$textBoxOutput.ReadOnly = $true +$form.Controls.Add($textBoxOutput) + +# Event handler for the ComboBox selection change +$comboBoxNumUsers.Add_SelectedIndexChanged({ + $numUsers = [int]$comboBoxNumUsers.SelectedItem + + # Show/hide textboxes based on the selected number of users + $textBoxUser1.Visible = $numUsers -ge 1 + $textBoxUser2.Visible = $numUsers -ge 2 + $textBoxUser3.Visible = $numUsers -ge 3 +}) + +# Event handler for the Compare button +$buttonCompare.Add_Click({ + # Get the entered UPNs and the selected number of users + $primaryUserUPN = $textBoxPrimaryUser.Text + $numUsers = [int]$comboBoxNumUsers.SelectedItem + + # Get the UPNs of the users to compare against based on the selected number + $usersToCompareUPNs = @() + if ($textBoxUser1.Visible) { $usersToCompareUPNs += $textBoxUser1.Text } + if ($textBoxUser2.Visible) { $usersToCompareUPNs += $textBoxUser2.Text } + if ($textBoxUser3.Visible) { $usersToCompareUPNs += $textBoxUser3.Text } + + # Function to get group memberships for a user using UPN + function Get-ADUserGroupsByUPN { + param ( + [string]$userUPN + ) + + $user = Get-ADUser -Filter { UserPrincipalName -eq $userUPN } -Server $domaincontroller + if ($user) { + $groups = Get-ADPrincipalGroupMembership -Identity $user -Server $domaincontroller + return $groups | Select-Object -ExpandProperty Name + } else { + Write-Host "User with UPN $userUPN not found." + return $null + } + } + + # Get group memberships for the primary user + $primaryUserGroups = Get-ADUserGroupsByUPN -userUPN $primaryUserUPN + + if ($primaryUserGroups -ne $null) { + # Compare group memberships for the primary user with other users + $missingGroups = @() + + foreach ($userUPN in $usersToCompareUPNs) { + $userGroups = Get-ADUserGroupsByUPN -userUPN $userUPN + if ($userGroups -ne $null) { + foreach ($group in $userGroups) { + if ($primaryUserGroups -notcontains $group -and $missingGroups -notcontains $group) { + $missingGroups += $group + } + } + } + } + + # Display the missing groups in the output textbox + if ($missingGroups.Count -gt 0) { + $missingGroupsText = $missingGroups -join "`r`n" + $textBoxOutput.Text = "Groups missing for $primaryUserUPN compared to the other users:`r`n`r`n$missingGroupsText" + } else { + $textBoxOutput.Text = "No missing groups found for $primaryUserUPN." + } + } +}) + +# Event handler for the Help button +$buttonHelp.Add_Click({ + # Display usage instructions in a new window + $helpForm = New-Object Windows.Forms.Form + $helpForm.Text = "Usage Instructions" + $helpForm.Width = 400 + $helpForm.Height = 350 + + $helpLabel = New-Object Windows.Forms.Label + $helpLabel.Text = "Instructions:" + $helpLabel.Location = New-Object Drawing.Point(10, 10) + $helpForm.Controls.Add($helpLabel) + + $helpText = @" +1. Enter the UPN of the primary user in the 'Primary User UPN' field. + +2. Select the number of users to compare against from the dropdown 1, 2 or 3. + +3. Enter the UPNs of the users to compare against in the 'Users to Compare Against' section. + +4. Click the 'Compare' button to compare group memberships that the primary user is missing. + +5. The results will be displayed in the textbox below. Find the membership that is most likely what they need and apply this in AD. + +6. If this is an admin account, Please supply this information to Wintel via the ticket to be actioned accordingly. +"@ + $helpTextBox = New-Object Windows.Forms.TextBox + $helpTextBox.Location = New-Object Drawing.Point(10, 40) + $helpTextBox.Width = 360 + $helpTextBox.Height = 250 + $helpTextBox.Multiline = $true + $helpTextBox.ScrollBars = "Vertical" + $helpTextBox.Text = $helpText + $helpTextBox.ReadOnly = $true + $helpForm.Controls.Add($helpTextBox) + + $helpForm.ShowDialog() +}) + +# Show the form +$form.ShowDialog() + + +# Disclaimer: TWFkZSBieSBaYWsgQmVhcm1hbiAtIERhdGFjb20gV2ludGVsIC0gUHJvdmlkZWQgYXMgaXMgd2hlcmUgaXMuIElmIGJyb2tlbiB3aWxsIGJlIGxvb2tlZCBhdCBpbiBhIGJlc3QgZWZmb3J0IGF0dGVtcHQ= \ No newline at end of file diff --git a/Conversation.ps1 b/Conversation.ps1 new file mode 100644 index 0000000..2952c91 --- /dev/null +++ b/Conversation.ps1 @@ -0,0 +1,80 @@ +## After running the powershell scriopt run the following after the fact changing the port number to what you need. + +## $msg = Receive-TCPMessage -Port 9999 + +## from the remote server that you need to send the traffic from. Run the following with the port number you set to listen + +## Test-NetConnection win1962 -Port 9999 + +Function Receive-TCPMessage { + + Param ( + + [Parameter(Mandatory=$true, Position=0)] + + [ValidateNotNullOrEmpty()] + + [int] $Port + + ) + + Process { + + Try { + + # Set up endpoint and start listening + + $endpoint = new-object System.Net.IPEndPoint([ipaddress]::any,$port) + + $listener = new-object System.Net.Sockets.TcpListener $EndPoint + + $listener.start() + + + + # Wait for an incoming connection + + $data = $listener.AcceptTcpClient() + + + + # Stream setup + + $stream = $data.GetStream() + + $bytes = New-Object System.Byte[] 1024 + + + + # Read data from stream and write it to host + + while (($i = $stream.Read($bytes,0,$bytes.Length)) -ne 0){ + + $EncodedText = New-Object System.Text.ASCIIEncoding + + $data = $EncodedText.GetString($bytes,0, $i) + + Write-Output $data + + } + + + + # Close TCP connection and stop listening + + $stream.close() + + $listener.stop() + + } + + Catch { + + "Receive Message failed with: `n" + $Error[0] + + } + + } + +} + \ No newline at end of file diff --git a/Darth-SPooN.ps1 b/Darth-SPooN.ps1 new file mode 100644 index 0000000..0dc7414 --- /dev/null +++ b/Darth-SPooN.ps1 @@ -0,0 +1,111 @@ +param( + [Parameter(Mandatory = $true)] + [string]$MachineName, + + [Parameter(Mandatory = $true)] + [string]$ServiceAccount, + + [int]$SqlPort = 1433, + + [string[]]$HadrListeners +) + +Import-Module ActiveDirectory + +Write-Host "=== MSSQLSvc + HADR SPN Validation Tool ===" -ForegroundColor Cyan +Write-Host "Machine: $MachineName" +Write-Host "Service Account: $ServiceAccount" +Write-Host "SQL Port: $SqlPort" +if ($HadrListeners) { + Write-Host "HADR Listener(s): $($HadrListeners -join ', ')" +} +Write-Host "-------------------------------------------" + +# Get domain FQDN +$domainFQDN = (Get-ADDomain).DNSRoot + +# Lookup service account (user or computer) +try { + $svcObj = Get-ADUser -Identity $ServiceAccount -Properties ServicePrincipalName -ErrorAction Stop +} catch { + try { + $svcObj = Get-ADComputer -Identity $ServiceAccount -Properties ServicePrincipalName -ErrorAction Stop + } catch { + Write-Host "ERROR: Service account '$ServiceAccount' not found in AD." -ForegroundColor Red + exit + } +} + +# Build expected MSSQLSvc SPNs for machine and HADR listeners +$namesToCheck = @($MachineName) +if ($HadrListeners) { + $namesToCheck += $HadrListeners +} +$expectedSPNs = foreach ($name in $namesToCheck) { + "MSSQLSvc/${name}.${domainFQDN}:$SqlPort" + "MSSQLSvc/${name}:$SqlPort" +} + +Write-Host "`nExpected MSSQLSvc SPNs:" -ForegroundColor Yellow +$expectedSPNs | ForEach-Object { Write-Host " $_" } + +# Case-insensitive missing SPN check (fixed grouping) +$missingSPNs = $expectedSPNs | Where-Object { + $expectedLower = $_.ToLower() + -not (( $svcObj.ServicePrincipalName | ForEach-Object { $_.ToLower() } ) -contains $expectedLower) +} + +if ($missingSPNs) { + Write-Host "`n[!] Missing MSSQLSvc SPNs on service account:" -ForegroundColor Red + $missingSPNs | ForEach-Object { Write-Host " $_" -ForegroundColor Red } + + $addPrompt = Read-Host "`nDo you want to add the missing SPNs now? (Y/N)" + if ($addPrompt -match '^[Yy]$') { + foreach ($spn in $missingSPNs) { + Write-Host "Adding SPN: $spn" -ForegroundColor Green + # Use -S to avoid duplicates, requires running as an account with permission + setspn -S $spn $ServiceAccount + } + Write-Host "`n[OK] Missing SPNs have been added." -ForegroundColor Green + } else { + Write-Host "Skipping SPN creation." -ForegroundColor Yellow + } +} else { + Write-Host "`n[OK] All expected MSSQLSvc SPNs are present." -ForegroundColor Green +} + +# Pull all SPNs in the domain +$allSPNs = Get-ADObject -Filter {ServicePrincipalName -like "*"} -Properties ServicePrincipalName | + ForEach-Object { + foreach ($spn in $_.ServicePrincipalName) { + [PSCustomObject]@{ + SPN = $spn + ADObject = $_.SamAccountName + DN = $_.DistinguishedName + } + } + } + +# Check for duplicates of MSSQLSvc SPNs +Write-Host "`nChecking for duplicate MSSQLSvc SPNs in the domain..." -ForegroundColor Yellow +foreach ($spn in $svcObj.ServicePrincipalName | Where-Object { $_ -like "MSSQLSvc/*" }) { + $owners = $allSPNs | Where-Object { $_.SPN -eq $spn } + if ($owners.Count -gt 1) { + Write-Host "[DUPLICATE] SPN '$spn' is owned by multiple objects:" -ForegroundColor Red + $owners | ForEach-Object { Write-Host " -> $($_.ADObject) ($($_.DN))" } + } +} + +# Check for MSSQLSvc SPNs on service account that aren't expected +$expectedLowerList = $expectedSPNs | ForEach-Object { $_.ToLower() } +$wrongSPNs = $svcObj.ServicePrincipalName | Where-Object { + $_ -like "MSSQLSvc/*" -and ($_.ToLower() -notin $expectedLowerList) +} +if ($wrongSPNs) { + Write-Host "`n[!] Warning: Service account has MSSQLSvc SPNs not in expected list:" -ForegroundColor Red + $wrongSPNs | ForEach-Object { Write-Host " $_" } +} else { + Write-Host "`n[OK] No unexpected MSSQLSvc SPNs found." -ForegroundColor Green +} + +Write-Host "`n=== MSSQLSvc + HADR SPN Check Complete ===" diff --git a/EggBasket.ps1 b/EggBasket.ps1 new file mode 100644 index 0000000..1adb570 --- /dev/null +++ b/EggBasket.ps1 @@ -0,0 +1,132 @@ +# Load required assemblies +Add-Type -AssemblyName System.Windows.Forms +Add-Type -AssemblyName System.Drawing + +# Create the form +$form = New-Object System.Windows.Forms.Form +$form.Text = "MSA Creator - Khan Mayker" +$form.Size = New-Object System.Drawing.Size(400,400) +$form.StartPosition = "CenterScreen" + +# Create Labels and Textboxes for Variables +$labelSVCAccount = New-Object System.Windows.Forms.Label +$labelSVCAccount.Text = "Service Account Name:" +$labelSVCAccount.Location = New-Object System.Drawing.Point(10,20) +$labelSVCAccount.Size = New-Object System.Drawing.Size(150,20) +$form.Controls.Add($labelSVCAccount) + +$textSVCAccount = New-Object System.Windows.Forms.TextBox +$textSVCAccount.Location = New-Object System.Drawing.Point(180,20) +$textSVCAccount.Size = New-Object System.Drawing.Size(180,20) +$form.Controls.Add($textSVCAccount) + +$labelDNS = New-Object System.Windows.Forms.Label +$labelDNS.Text = "DNS Host Name:" +$labelDNS.Location = New-Object System.Drawing.Point(10,60) +$labelDNS.Size = New-Object System.Drawing.Size(150,20) +$form.Controls.Add($labelDNS) + +$textDNS = New-Object System.Windows.Forms.TextBox +$textDNS.Location = New-Object System.Drawing.Point(180,60) +$textDNS.Size = New-Object System.Drawing.Size(180,20) +$textDNS.Text = ".domain.placeholder.nz" # Enter your domain "domain.govt.nz" ##################### UPDATE THIS LINE ##################### +$textDNS.Enabled = $false +$form.Controls.Add($textDNS) + +$labelPath = New-Object System.Windows.Forms.Label +$labelPath.Text = "OU Path:" +$labelPath.Location = New-Object System.Drawing.Point(10,100) +$labelPath.Size = New-Object System.Drawing.Size(150,20) +$form.Controls.Add($labelPath) + +$textPath = New-Object System.Windows.Forms.TextBox +$textPath.Location = New-Object System.Drawing.Point(180,100) +$textPath.Size = New-Object System.Drawing.Size(180,20) +$textPath.Text = "OU=grMSA,OU=Service Accounts,OU=_Administration,DC=domain,DC=placeholder,DC=nz" ##################### UPDATE THIS LINE ##################### +$textPath.Enabled = $false +$form.Controls.Add($textPath) + +$labelMachines = New-Object System.Windows.Forms.Label +$labelMachines.Text = "Machine Names (comma-separated):" +$labelMachines.Location = New-Object System.Drawing.Point(10,140) +$labelMachines.Size = New-Object System.Drawing.Size(220,20) +$form.Controls.Add($labelMachines) + +$textMachines = New-Object System.Windows.Forms.TextBox +$textMachines.Location = New-Object System.Drawing.Point(10,170) +$textMachines.Size = New-Object System.Drawing.Size(350,20) +$form.Controls.Add($textMachines) + +# Event to update DNS field based on Service Account Name input +$textSVCAccount.Add_TextChanged({ + $textDNS.Text = "$($textSVCAccount.Text).domain.placeholder.nz" ##################### UPDATE THIS LINE ##################### +}) + +# Create the Submit Button +$buttonSubmit = New-Object System.Windows.Forms.Button +$buttonSubmit.Text = "Create MSA and AD Group" +$buttonSubmit.Location = New-Object System.Drawing.Point(120, 210) +$buttonSubmit.Size = New-Object System.Drawing.Size(150,30) +$form.Controls.Add($buttonSubmit) + +# Action on Submit Button Click +$buttonSubmit.Add_Click({ + $SVCAccount = $textSVCAccount.Text + $dns = $textDNS.Text + $path = "OU=grMSA,OU=Service Accounts,OU=_Administration,DC=domain,DC=placeholder,DC=nz" ##################### UPDATE THIS LINE ##################### + $machines = $textMachines.Text.Split(',') + + if (-not [string]::IsNullOrWhiteSpace($SVCAccount) -and -not [string]::IsNullOrWhiteSpace($dns) -and -not [string]::IsNullOrWhiteSpace($path) -and $machines.Count -gt 0) { + + $grMSA = "grMSA_$SVCAccount" + + try { + # Create AD Group + New-ADGroup -Name $grMSA -Path $path -GroupScope Global -PassThru -Verbose + + # Add Machines to AD Group + foreach ($machine in $machines) { + $machineTrimmed = $machine.Trim() + '$' + Add-AdGroupMember -Identity $grMSA -Members $machineTrimmed -Verbose + } + + # Create MSA with the AD Group allowed to retrieve the password + New-ADServiceAccount -Name $SVCAccount -DNSHostName $dns -PrincipalsAllowedToRetrieveManagedPassword $grMSA -Verbose + + [System.Windows.Forms.MessageBox]::Show("MSA and AD Group created successfully.", "Success", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information) + } catch { + [System.Windows.Forms.MessageBox]::Show("Error: $_", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error) + } + } else { + [System.Windows.Forms.MessageBox]::Show("Please fill in all fields.", "Input Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Warning) + } +}) + +# Hidden Feature: Click bottom-left corner to open a new window with the message +$form.Add_MouseClick({ + param($sender, $e) + + # Check if the click is at the bottom-left corner + if ($e.X -eq 0 -and $e.Y -eq $form.ClientSize.Height - 1) { + $hiddenForm = New-Object System.Windows.Forms.Form + $hiddenForm.Text = "Hidden Message" + $hiddenForm.Size = New-Object System.Drawing.Size(500,200) + $hiddenForm.StartPosition = "CenterScreen" + + $textBoxMessage = New-Object System.Windows.Forms.TextBox + $textBoxMessage.Multiline = $true + $textBoxMessage.ReadOnly = $true + $textBoxMessage.Text = "dKU0fKP6Ob9ne29wOpCkepUyeV5me20yg2oudV9OdJIxA01khZwbLcs+RqUohKT9YJkoMWLzV2kkelXbPH1khZwbMWLze3LoPmE0dJXveZIselXbPJIxgJIqe25sf3ToPmEyClXbPHUye20oPmEIgJYbepIvOj== d" + $textBoxMessage.Location = New-Object System.Drawing.Point(10,20) + $textBoxMessage.Size = New-Object System.Drawing.Size(460,100) + $textBoxMessage.ScrollBars = "Vertical" + $hiddenForm.Controls.Add($textBoxMessage) + + $hiddenForm.ShowDialog() + } +}) + +# Show the form +$form.Topmost = $true +$form.Add_Shown({$form.Activate()}) +[void]$form.ShowDialog() diff --git a/Haystack.ps1 b/Haystack.ps1 new file mode 100644 index 0000000..1beae89 --- /dev/null +++ b/Haystack.ps1 @@ -0,0 +1,91 @@ +############################################################## +## Change Log # +## 1.0 Initial release # +## 1.1 Added logic for resolved IP to be displayed on screen.# +############################################################## + + +Add-Type -AssemblyName System.Windows.Forms +Add-Type -AssemblyName System.Drawing + +# Create form controls +$form = New-Object System.Windows.Forms.Form +$form.Text = "Haystack" +$form.ClientSize = New-Object System.Drawing.Size(400, 270) + +$dnsNameLabel = New-Object System.Windows.Forms.Label +$dnsNameLabel.Text = "A Record:" +$dnsNameLabel.Location = New-Object System.Drawing.Point(10, 20) +$dnsNameLabel.AutoSize = $true + +$dnsNameTextbox = New-Object System.Windows.Forms.TextBox +$dnsNameTextbox.Location = New-Object System.Drawing.Point(120, 20) +$dnsNameTextbox.Size = New-Object System.Drawing.Size(250, 20) + +$zoneLabel = New-Object System.Windows.Forms.Label +$zoneLabel.Text = "DNS Zone:" +$zoneLabel.Location = New-Object System.Drawing.Point(10, 50) +$zoneLabel.AutoSize = $true + +$zoneTextbox = New-Object System.Windows.Forms.TextBox +$zoneTextbox.Location = New-Object System.Drawing.Point(120, 50) +$zoneTextbox.Size = New-Object System.Drawing.Size(250, 20) + +$ipLabel = New-Object System.Windows.Forms.Label +$ipLabel.Text = "IP Address:" +$ipLabel.Location = New-Object System.Drawing.Point(10, 80) +$ipLabel.Size = New-Object System.Drawing.Size(62, 10) +$form.Controls.Add($ipLabel) + +$ipTextBox = New-Object System.Windows.Forms.TextBox +$ipTextBox.Location = New-Object System.Drawing.Point(10, 100) +$ipTextBox.ReadOnly = $true +$form.Controls.Add($ipTextBox) + +$createButton = New-Object System.Windows.Forms.Button +$createButton.Location = New-Object System.Drawing.Point(120, 80) +$createButton.Size = New-Object System.Drawing.Size(150, 23) +$createButton.Text = "Create Zone and A Record" +$createButton.Add_Click({ + # Combine fields and ping DNS name + $combined = $dnsNameTextbox.Text + "." + $zoneTextbox.Text + $pingResult = Test-Connection -ComputerName $combined -Count 1 -Quiet + + # Get IP address using Resolve-DnsName + $ipAddress = "" + $dnsResult = Resolve-DnsName -Name $combined -Type A -ErrorAction SilentlyContinue + if ($dnsResult) { + $ipAddress = $dnsResult.IPAddress + } + + # If ping failed and Resolve-DnsName didn't return an IP address, show error message and exit + if (!$pingResult -and !$dnsResult) { + [System.Windows.Forms.MessageBox]::Show("Could not resolve DNS name.") + return + } + + # Create DNS zone and A record + $zoneName = $zoneTextbox.Text + $aRecord = $dnsNameTextbox.Text + if ($ipAddress) { + $aRecord = $ipAddress + } + Add-DnsServerPrimaryZone -Name $combined -ZoneFile $zoneName + Add-DnsServerResourceRecordA -Name $combined -ZoneName $combined -IPv4Address $aRecord + [System.Windows.Forms.MessageBox]::Show("DNS zone and A record created successfully.") +}) + + $ipTextBox.Text = $ipAddress + +# Add controls to form +$form.Controls.Add($dnsNameLabel) +$form.Controls.Add($dnsNameTextbox) +$form.Controls.Add($zoneLabel) +$form.Controls.Add($zoneTextbox) +$form.Controls.Add($createButton) +$form.Controls.Add($pictureBox) +$form.Controls.Add($ipLabel) +$form.Controls.Add($ipTextBox) + +# Show the form +$form.ShowDialog() | Out-Null \ No newline at end of file diff --git a/Ledger.ps1 b/Ledger.ps1 new file mode 100644 index 0000000..286c287 --- /dev/null +++ b/Ledger.ps1 @@ -0,0 +1,29 @@ +#This script will read a CSV file with users in samaccountname format in a column named username and query AD for the last password set time based on the day count on line 11. + +# Define the path to the CSV file +$csvPath = "C:\temp\password-last-set.csv" # create a CSV file in a specific path with a column named username + +# Import the CSV file +$users = Import-Csv -Path $csvPath + +# Set the threshold in days +$thresholdDays = 0 + +# Calculate the threshold date +$thresholdDate = (Get-Date).AddDays(-$thresholdDays) + +# Iterate through each user in the CSV +foreach ($user in $users) { + # Get the SamAccountName from the CSV + $samAccountName = $user.username + + # Get the user object from Active Directory + $adUser = Get-ADUser -Filter { SamAccountName -eq $samAccountName } -Properties LastLogon + + # Check if the PasswordLastSet property exists and compare it with the threshold date + if ($null -eq $adUser.LastLogon) { + Write-Output "$samAccountName Password still unset" + } elseif ($adUser.LastLogon -lt $thresholdDate) { + Write-Output "$samAccountName Password was last set on $($adUser.PasswordLastSet)" + } +} diff --git a/Perfmon-Template.xml b/Perfmon-Template.xml new file mode 100644 index 0000000..e741c46 --- /dev/null +++ b/Perfmon-Template.xml @@ -0,0 +1,108 @@ + + + 0 + 0 + + + + + + + + + -1 + + + Overall + C:\temp\Perf\ + C:\temp\Perf + 0 + 0 + 0 + 1 + + + + + 0 + + + + + 0 + + + + + local_admin + O:BAG:DUD:AI(A;;FA;;;SY)(A;;FA;;;BA)(A;;FR;;;LU)(A;;0x1301ff;;;S-1-5-80-2661322625-712705077-2999183737-3043590567-590698655)(A;ID;FA;;;SY)(A;ID;FA;;;BA)(A;ID;0x1200ab;;;LU)(A;ID;FR;;;AU)(A;ID;FR;;;LS)(A;ID;FR;;;NS) + 0 + + 0 + System Monitor Log + P2 Performance Log + 1 + + + 0 + 0 + 0 + + + + + 1 + 0 + 3 + \Processor Information(_Total)\% Processor Time + \LogicalDisk(_Total)\% Disk Time + \LogicalDisk(_Total)\Avg. Disk Queue Length + \LogicalDisk(_Total)\Disk Reads/sec + \LogicalDisk(_Total)\Disk Writes/sec + \LogicalDisk(_Total)\Avg. Disk sec/Read + \LogicalDisk(_Total)\Avg. Disk sec/Write + \Memory\% Committed Bytes In Use + \Memory\Available MBytes + \Memory\Cache Faults/sec + \Memory\Committed Bytes + \Memory\Pages/sec + \Processor(*)\% Idle Time + \Processor(*)\% Privileged Time + \Processor(_Total)\% Processor Time + \System\Processor Queue Length + \System\Context Switches/sec + \System\System Calls/sec + \System\Threads + \Processor Information(_Total)\% Processor Time + \LogicalDisk(_Total)\% Disk Time + \LogicalDisk(_Total)\Avg. Disk Queue Length + \LogicalDisk(_Total)\Disk Reads/sec + \LogicalDisk(_Total)\Disk Writes/sec + \LogicalDisk(_Total)\Avg. Disk sec/Read + \LogicalDisk(_Total)\Avg. Disk sec/Write + \Memory\% Committed Bytes In Use + \Memory\Available MBytes + \Memory\Cache Faults/sec + \Memory\Committed Bytes + \Memory\Pages/sec + \Processor(*)\% Idle Time + \Processor(*)\% Privileged Time + \Processor(_Total)\% Processor Time + \System\Processor Queue Length + \System\Context Switches/sec + \System\System Calls/sec + \System\Threads + + + 0 + 0 + 0 + 0 + 0 + 0 + report.html + report.xml + + + + diff --git a/Scope.ps1 b/Scope.ps1 new file mode 100644 index 0000000..5300d2b --- /dev/null +++ b/Scope.ps1 @@ -0,0 +1,58 @@ +param ( + [string]$CAName, # Specify the CA name to search for + [switch]$Valid, # Show only valid certificates + [switch]$Invalid # Show only invalid certificates +) + +if (-not $CAName) { + $CAName = "NZGOVTCA*" +} + +# Define certificate stores +$rootStore = "Cert:\LocalMachine\Root" +$intermediateStore = "Cert:\LocalMachine\CA" + +# Function to check certificate validity +function Check-CertificateValidity { + param ($Cert, $StoreName) + + # Get current date + $currentDate = Get-Date + + # Check expiration and validity period + $isValid = $currentDate -ge $Cert.NotBefore -and $currentDate -le $Cert.NotAfter + + # Prepare result object + [PSCustomObject]@{ + Store = $StoreName + Subject = $Cert.Subject + Issuer = $Cert.Issuer + Thumbprint = $Cert.Thumbprint + ValidFrom = $Cert.NotBefore + ValidTo = $Cert.NotAfter + Status = if ($isValid) { "Valid" } else { "Invalid" } + } +} + +# Get all root and intermediate certificates issued by the specified CA +$rootCerts = Get-ChildItem -Path $rootStore | Where-Object { $_.Issuer -like "*$CAName*" } +$intermediateCerts = Get-ChildItem -Path $intermediateStore | Where-Object { $_.Issuer -like "*$CAName*" } + +# Check certificates +$results = @() +$results += $rootCerts | ForEach-Object { Check-CertificateValidity -Cert $_ -StoreName "Root CA" } +$results += $intermediateCerts | ForEach-Object { Check-CertificateValidity -Cert $_ -StoreName "Intermediate CA" } + +# Apply filtering based on switches +if ($Valid) { + $results = $results | Where-Object { $_.Status -eq "Valid" } +} elseif ($Invalid) { + $results = $results | Where-Object { $_.Status -eq "Invalid" } +} + +# Output results +if ($results.Count -eq 0) { + Write-Host "No certificates found matching the criteria." -ForegroundColor Red +} else { + $results | Format-Table -AutoSize +} diff --git a/Stacker.ps1 b/Stacker.ps1 new file mode 100644 index 0000000..ac1dabc --- /dev/null +++ b/Stacker.ps1 @@ -0,0 +1,33 @@ +# Variables +$CsrFolder = "C:\Temp\CSRs" # Path to folder with CSR files +$DnsZone = "record.domain.govt.nz" # Your DNS zone (AD-integrated) +$TargetIP = "managementboxIP" # The IP for all A records +$DnsServer = "DC01.example.local" # AD Domain Controller / DNS server + +# Loop through CSR files +Get-ChildItem -Path $CsrFolder -Filter *.csr | ForEach-Object { + # Get just the file name without extension + $fqdn = $_.BaseName.Trim() + Write-Host "Processing $fqdn ..." + + try { + # If the filename is a full FQDN, strip the zone name + if ($fqdn.ToLower().EndsWith(".$($DnsZone.ToLower())")) { + $hostname = $fqdn.Substring(0, $fqdn.Length - $DnsZone.Length - 1) + } else { + $hostname = $fqdn + } + + Write-Host " -> Adding DNS A record for $hostname.$DnsZone -> $TargetIP" + + Add-DnsServerResourceRecordA ` + -Name $hostname ` + -ZoneName $DnsZone ` + -IPv4Address $TargetIP ` + -ComputerName $DnsServer ` + -ErrorAction Stop + + } catch { + Write-Warning "Could not add DNS record for $fqdn : $_" + } +} diff --git a/Tentacles.ps1 b/Tentacles.ps1 new file mode 100644 index 0000000..5cd5267 --- /dev/null +++ b/Tentacles.ps1 @@ -0,0 +1,46 @@ +# Paths +$WacsPath = "C:\ProgramData\Wacs\wacs.exe" +$CsrFolder = "C:\Temp\Renew\Video" +$OutFolder = "C:\Temp\Renew\Output" + +# Collect CSR files +$csrFiles = Get-ChildItem -Path $CsrFolder -Include *.csr, *.pem -File -Recurse + +if (-not $csrFiles) { + Write-Host "No CSR files found in $CsrFolder" + exit +} + +foreach ($csr in $csrFiles) { + # Use the base filename (without extension) as the hostname + $baseName = [System.IO.Path]::GetFileNameWithoutExtension($csr.Name) + $outPath = Join-Path $OutFolder ($baseName + ".pfx") + + # Ensure the output directory exists + $outDir = Split-Path $outPath -Parent + if (-not (Test-Path $outDir)) { + New-Item -Path $outDir -ItemType Directory -Force | Out-Null + } + + # Build argument array (manual target, hostname from filename) + $args = @( + "--target", "manual", + "--host", $baseName, + "--store", "pfxfile", + "--pfxfilepath", "C:\programdata\wacs\output\", + "--baseuri", "https://acmeprod.domain.govt.nz:9999/acme/rsa/", + "--validation", "selfhosting", + "--validationport", "9998", + "--verbose" + ) + + # Print command for verification + Write-Host "`nReady to run WACS command for $($csr.Name):" + Write-Host "& $WacsPath $($args -join ' ')" + + # Run WACS + & $WacsPath @args + Write-Host "Done processing $($csr.Name)" +} + +Write-Host "`nAll CSR filenames processed as hostnames." diff --git a/Warden.ps1 b/Warden.ps1 new file mode 100644 index 0000000..49b493a --- /dev/null +++ b/Warden.ps1 @@ -0,0 +1,153 @@ +Add-Type -AssemblyName System.Windows.Forms + +# Create the form +$form = New-Object System.Windows.Forms.Form +$form.Text = "Instructions" +$form.Size = New-Object System.Drawing.Size(800, 550) +$form.StartPosition = "CenterScreen" + +# Create a label to display the instructions +$label = New-Object System.Windows.Forms.Label +$label.Text = @" +This script will read a CSV file with users in samaccountname format in a column named 'username' and will set the -ChangePasswordAtLogon property to $true. + +Please select the CSV file. + +Clicking Accept will proceed with the operation. Make sure you have confirmed the CSV file is correct before proceeding. +"@ +$label.AutoSize = $true +$label.MaximumSize = New-Object System.Drawing.Size(560, 0) # Set maximum width and allow height to adjust +$label.Location = New-Object System.Drawing.Point(10, 80) +$form.Controls.Add($label) + +# Define author information +$authorName = "Zak Bearman" +$department = "Wintel Platforms" +$year = "2025" + +# Create a label to display the author +$label2 = New-Object System.Windows.Forms.Label +$label2.Text = "Written by $authorName - $department $year." +$label2.AutoSize = $true +$label2.MaximumSize = New-Object System.Drawing.Size(560, 0) # Set maximum width and allow height to adjust +$label2.Location = New-Object System.Drawing.Point(160, 420) +$form.Controls.Add($label2) + +# Create a TextBox to display the CSV content +$textBox = New-Object System.Windows.Forms.TextBox +$textBox.Multiline = $true +$textBox.ScrollBars = "Vertical" +$textBox.ReadOnly = $true +$textBox.Size = New-Object System.Drawing.Size(200, 500) +$textBox.Location = New-Object System.Drawing.Point(568, 5) +$form.Controls.Add($textBox) + +# Create a button to browse for the CSV file +$browseButton = New-Object System.Windows.Forms.Button +$browseButton.Text = "Browse" +$browseButton.Location = New-Object System.Drawing.Point(250, 240) +$script:csvPath = $null +$browseButton.Add_Click({ + $script:csvPath = $null + $openFileDialog = New-Object System.Windows.Forms.OpenFileDialog + $openFileDialog.Filter = "CSV files (*.csv)|*.csv" + if ($openFileDialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { + $script:csvPath = $openFileDialog.FileName + $textBox.Text = Get-Content -Path $script:csvPath -Raw + } +}) +$form.Controls.Add($browseButton) + +# Create an Accept button +$acceptButton = New-Object System.Windows.Forms.Button +$acceptButton.Text = "Accept" +$acceptButton.Location = New-Object System.Drawing.Point(200, 300) +$acceptButton.Add_Click({ + if (-not $script:csvPath) { + [System.Windows.Forms.MessageBox]::Show("No CSV file selected. Please select a CSV file to proceed.", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error) + return + } + $form.Tag = "Accept" + $form.Close() +}) +$form.Controls.Add($acceptButton) + +# Create a Cancel button +$cancelButton = New-Object System.Windows.Forms.Button +$cancelButton.Text = "Cancel" +$cancelButton.Location = New-Object System.Drawing.Point(300, 300) +$cancelButton.Add_Click({ + $form.Tag = "Cancel" + $form.Close() +}) +$form.Controls.Add($cancelButton) + +# Show the form +$form.ShowDialog() + +# Check the form result +if ($form.Tag -eq "Cancel") { + Write-Output "Operation cancelled by the user." + exit +} + +# Import the CSV file +$userList = Import-Csv -Path $script:csvPath + +# Check if the path exists, if not create it +$destinationPath = "C:\temp\useroutput\done" +if (-not (Test-Path -Path $destinationPath)) { + New-Item -ItemType Directory -Path $destinationPath | Out-Null +} + +# Get today's date +$todaysDate = Get-Date -Format "yyyyMMdd" + +# Set the output CSV file path +$outputCsvPath = "$destinationPath\users-done-$todaysDate.csv" + +# Loop through each user in the CSV +foreach ($user in $userList) { + $samAccountName = $user.username + + try { + # Get the user object by SamAccountName + $userObject = Get-ADUser -Filter {SamAccountName -eq $samAccountName} + + if ($null -eq $userObject) { + throw "User '$samAccountName' does not exist." + } + + # Set the password to expired + Set-ADUser -Identity $samAccountName -ChangePasswordAtLogon $true + + Write-Output "Password for user '$samAccountName' has been set to expired." + } + catch { + Write-Output "Failed to set password for user '$samAccountName': $_" + } +} + catch { + Write-Output "Failed to set password for user '$samAccountName': $_" + } +# Export the updated user list to the new CSV file +$userList | Export-Csv -Path $outputCsvPath -NoTypeInformation + +Write-Output "The updated user list has been exported to $outputCsvPath." + +# Rename the source CSV file +$originalFileName = [System.IO.Path]::GetFileNameWithoutExtension($script:csvPath) +$originalFileExtension = [System.IO.Path]::GetExtension($script:csvPath) +$directory = [System.IO.Path]::GetDirectoryName($script:csvPath) +$newFileName = "$originalFileName-done-$todaysDate$originalFileExtension" +$newFilePath = [System.IO.Path]::Combine($directory, $newFileName) + +Rename-Item -Path $script:csvPath -NewName $newFileName + +Write-Output "The original CSV file has been renamed to $newFilePath." + +# Open the folder containing the renamed CSV file +Start-Process -FilePath "explorer.exe" -ArgumentList "/select,`"$newFilePath`"" + +# Clear all variables from active memory +Remove-Variable -Name form, label, label2, textBox, browseButton, acceptButton, cancelButton, csvPath, userList, destinationPath, todaysDate, outputCsvPath, originalFileName, originalFileExtension, directory, newFileName, newFilePath -ErrorAction SilentlyContinue \ No newline at end of file