diff --git a/MoreInfoWindow.ps1 b/MoreInfoWindow.ps1 new file mode 100644 index 0000000..2def85c --- /dev/null +++ b/MoreInfoWindow.ps1 @@ -0,0 +1,75 @@ +param ( + [string[]]$Items, + [string]$Title = 'ADGroups' +) +Add-Type -AssemblyName System.Windows.Forms + +# Create the Form +$form = New-Object System.Windows.Forms.Form +$form.Text = $Title +$form.Size = New-Object System.Drawing.Size(410, 300) +$form.StartPosition = "CenterScreen" +$form.MinimumSize = New-Object System.Drawing.Size(200, 200) +$form.MaximizeBox = $false +$form.FormBorderStyle = 'SizableToolWindow' + +# Pressing `Esc` closes the form +$form.KeyPreview = $true +$form.Add_KeyUp({ + param($sender, $e) + if ($e.KeyCode -eq [System.Windows.Forms.Keys]::Escape) { + $sender.Close() + } + }) + +# Create the ListView +$listView = New-Object System.Windows.Forms.ListView +$listView.View = [System.Windows.Forms.View]::Details +$listView.FullRowSelect = $true +$listView.Columns.Add("Items", 385) +$listView.Anchor = [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Left -bor [System.Windows.Forms.AnchorStyles]::Right -bor [System.Windows.Forms.AnchorStyles]::Bottom +$listView.Height = 200 +$listView.Width = 390 + +# Add provided items to ListView +$Items | ForEach-Object { + $item = New-Object System.Windows.Forms.ListViewItem($_) + $listView.Items.Add($item) +} + +$listView.AutoResizeColumns([System.Windows.Forms.ColumnHeaderAutoResizeStyle]::ColumnContent) + +# Create Panel for Buttons +$buttonFlow = New-Object System.Windows.Forms.FlowLayoutPanel +$buttonFlow.Dock = [System.Windows.Forms.DockStyle]::Bottom +$buttonFlow.FlowDirection = [System.Windows.Forms.FlowDirection]::RightToLeft +$buttonFlow.Height = 40 +$form.Controls.Add($buttonFlow) + +# Uniform button size +$buttonSize = New-Object System.Drawing.Size(75, 25) + +# Create the Close Button +# $closeButton = New-Object System.Windows.Forms.Button +# $closeButton.Text = "Close" +# $closeButton.Size = $buttonSize +# $closeButton.Add_Click({ $form.Close() }) +# $buttonFlow.Controls.Add($closeButton) +# $form.CancelButton = $closeButton + +# Create the Copy Button +$copyButton = New-Object System.Windows.Forms.Button +$copyButton.Text = "Copy" +$copyButton.Size = $buttonSize +$copyButton.Add_Click({ + if ($listView.SelectedItems.Count -gt 0) { + [System.Windows.Forms.Clipboard]::SetText($listView.SelectedItems[0].Text) + } + }) +$buttonFlow.Controls.Add($copyButton) + +# Add controls to form +$form.Controls.Add($listView) + +# Show the Form +$form.ShowDialog() \ No newline at end of file diff --git a/Show-ADUserInfo.ps1 b/Show-ADUserInfo.ps1 index ba320b6..8f437ef 100644 --- a/Show-ADUserInfo.ps1 +++ b/Show-ADUserInfo.ps1 @@ -1,3 +1,7 @@ +param( + [string]$Username +) + Add-Type -AssemblyName System.Windows.Forms function Get-ADUserInfo { @@ -6,46 +10,20 @@ function Get-ADUserInfo { ) try { - if ($Debug -eq $true) { - # Simulated test data - $PasswordLastSetDate = [datetime]"2024-03-01" - $DaysSincePassword = (New-TimeSpan -Start $PasswordLastSetDate -End (Get-Date)).Days - - $User = [PSCustomObject]@{ - Name = "John Doe" - SamAccountName = "jdoe" - Office = "New York" - Email = "jdoe@example.com" - Info = "Test user for GUI" - CustomAttribute15 = "Test Attribute" - Manager = "Jane Smith" - Title = "IT Specialist" - Department = "IT" - LockedOut = "False" - PasswordExpired = "False" - PasswordLastSet = $PasswordLastSetDate.ToString("yyyy-MM-dd") - MemberOf = "Domain Users, IT Group" - } - $User | Add-Member -MemberType NoteProperty -Name DaysSincePassword -Value "$DaysSincePassword" - $User | Add-Member -MemberType AliasProperty -Name Username -Value SamAccountName - $User | Add-Member -MemberType AliasProperty -Name CostCenter -Value CustomAttribute15 - } - else { - # Retrieve real data from AD - $User = Get-ADUser -Identity $SamAccountName -Properties Office, EmailAddress, Info, CustomAttribute15, Manager, Title, Department, LockedOut, PasswordExpired, PasswordLastSet, MemberOf + # Retrieve real data from AD + $User = Get-ADUser -Identity $SamAccountName -Properties Office, Mail, Info, ExtensionAttribute15, Manager, Title, Department, LockedOut, PasswordExpired, PasswordLastSet, MemberOf, IPPhone - if ($User) { - $PasswordLastSetDate = $User.PasswordLastSet - $DaysSincePassword = (New-TimeSpan -Start $PasswordLastSetDate -End (Get-Date)).Days - $Manager = if ($User.Manager) { (Get-ADUser -Identity $User.Manager).Name } else { "N/A" } - $MemberOf = ($User.MemberOf | Get-ADGroup | Select-Object -ExpandProperty Name) -join ", " + if ($User) { + $PasswordLastSetDate = $User.PasswordLastSet + $DaysSincePassword = (New-TimeSpan -Start $PasswordLastSetDate -End (Get-Date)).Days + # $Manager = if ($User.Manager) { (Get-ADUser -Identity $User.Manager).Name } else { "N/A" } + # $MemberOf = ($User.MemberOf | Get-ADGroup | Select-Object -ExpandProperty Name) -join ", " - $User | Add-Member -MemberType NoteProperty -Name DaysSincePassword -Value "$DaysSincePassword" - $User | Add-Member -MemberType AliasProperty -Name Username -Value SamAccountName - $User | Add-Member -MemberType AliasProperty -Name CostCenter -Value CustomAttribute15 - } + $User | Add-Member -Force -MemberType NoteProperty -Name DaysSincePassword -Value "$DaysSincePassword" + $User | Add-Member -Force -MemberType AliasProperty -Name Username -Value SamAccountName + $User | Add-Member -Force -MemberType AliasProperty -Name CostCenter -Value ExtensionAttribute15 } - + Write-Host $user return $User } catch { @@ -54,11 +32,15 @@ function Get-ADUserInfo { return $null } +#region Form setup + # Create the Form $form = New-Object System.Windows.Forms.Form $form.Text = "AD User Information" -$form.StartPosition = "CenterScreen" -$form.Size = New-Object System.Drawing.Size(550, 500) +# $form.StartPosition = "CenterScreen" +$form.Size = New-Object System.Drawing.Size(550, 510) +$form.MaximizeBox = $false +$form.FormBorderStyle = 'FixedDialog' # Create TableLayoutPanel $tableLayout = New-Object System.Windows.Forms.TableLayoutPanel @@ -75,10 +57,14 @@ $tableLayout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([Syst $tableLayout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::AutoSize))) $tableLayout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle([System.Windows.Forms.SizeType]::AutoSize))) +#endregion + +#region User Info Rows + # Define AutoComplete source $autoComplete = New-Object System.Windows.Forms.AutoCompleteStringCollection $allADUsers = Get-ADUser -Filter * -Properties Name, SamAccountName -$autoComplete.AddRange($allADUsers.SamAccountName) +$autoComplete.AddRange($allADUsers.SamAccountName -split " ") # Username Input Row $tableLayout.RowCount++ @@ -100,26 +86,63 @@ $tableLayout.RowCount++ $tableLayout.Controls.Add((New-Object System.Windows.Forms.Label -Property @{Text = "" }), 0, $tableLayout.RowCount - 1) $tableLayout.SetColumnSpan((New-Object System.Windows.Forms.Label -Property @{Text = "" }), 6) -# Labels, Read-Only Text Fields, and Copy Buttons for Results -$fields = @("Name", "Username", "Office", "Email", "Info", "CostCenter", "Manager", "Title", "Department", "MemberOf") -$textBoxes = @{} - -foreach ($field in $fields) { +function Add-UserInfoRow ([string]$fieldName, [string]$buttonName, [scriptblock]$buttonAction) { $tableLayout.RowCount++ - $tableLayout.Controls.Add((New-Object System.Windows.Forms.Label -Property @{Text = "$field`:" }), 0, $tableLayout.RowCount - 1) - + $tableLayout.Controls.Add((New-Object System.Windows.Forms.Label -Property @{Text = "$fieldName`:" }), 0, $tableLayout.RowCount - 1) + $textBox = New-Object System.Windows.Forms.TextBox -Property @{ReadOnly = $true; Width = 300 } $tableLayout.SetColumnSpan($textBox, 4) $tableLayout.Controls.Add($textBox, 1, $tableLayout.RowCount - 1) - $textBoxes[$field] = $textBox - - $copyButton = New-Object System.Windows.Forms.Button -Property @{Text = "Copy"} - $copyButton.Tag = $textBox - $copyButton.Add_Click({ - param($sender, $eventArgs) - [System.Windows.Forms.Clipboard]::SetText($sender.Tag.Text) - }) - $tableLayout.Controls.Add($copyButton, 5, $tableLayout.RowCount - 1) + $textBoxes[$fieldName] = $textBox + + $button = New-Object System.Windows.Forms.Button -Property @{Text = $buttonName } + $button.Tag = $textBox + if ($buttonName -ieq "Copy") { + $button.Add_Click({ + param($sender, $eventArgs) + [System.Windows.Forms.Clipboard]::SetText($sender.Tag.Text) + }) + } + elseif ($buttonName -ieq "More...") { + $button.Add_Click($buttonAction) + } + else { + throw "Invalid button type." + } + $tableLayout.Controls.Add($button, 5, $tableLayout.RowCount - 1) + $buttons[$fieldName] = $button +} + +# Labels, Read-Only Text Fields, and Copy Buttons for Results +$fields = @("Name", "Username", "Office", "Mail", "IPPhone", "Info", "CostCenter", "Manager", "Title", "Department", "MemberOf", "LockedOut", "PasswordExpired", "PasswordLastSet", "DaysSincePassword") +$textBoxes = @{} +$buttons = @{} + +Add-UserInfoRow Name Copy +Add-UserInfoRow Username Copy +Add-UserInfoRow Office Copy +Add-UserInfoRow Mail Copy +Add-UserInfoRow IPPhone Copy +Add-UserInfoRow Info Copy +Add-UserInfoRow CostCenter Copy +Add-UserInfoRow Manager "More..." { + param($sender, $eventArgs) + [System.Windows.Forms.Cursor]::Current = [System.Windows.Forms.Cursors]::WaitCursor + $managerUsername = (Get-ADUser $textBoxes['Manager'].Text).SamAccountName + . $PSScriptRoot\Show-ADUserInfo.ps1 $managerUsername + [System.Windows.Forms.Cursor]::Current = [System.Windows.Forms.Cursors]::Default +} +Add-UserInfoRow Title Copy +Add-UserInfoRow Department Copy +Add-UserInfoRow MemberOf "More..." { + param($sender, $eventArgs) + $groups = (Get-ADUser $textBoxes['Username'].Text -Properties MemberOf).MemberOf + $groupNames = @() + foreach ($group in $groups) { + $groupNames += (Get-ADGroup $group -ErrorAction SilentlyContinue).Name ?? $group + } + $groupNames = $groupNames | Sort-Object + . $PSScriptRoot\MoreInfoWindow.ps1 $groupNames "AD Groups - $($textBoxes['Username'].Text)" } # Place LockedOut and PasswordExpired on the same row @@ -149,22 +172,162 @@ $textDaysSincePassword = New-Object System.Windows.Forms.TextBox -Property @{Rea $tableLayout.SetColumnSpan($textDaysSincePassword, 2) $tableLayout.Controls.Add($textDaysSincePassword, 4, $tableLayout.RowCount - 1) $textBoxes["DaysSincePassword"] = $textDaysSincePassword +$toolPasswordExpiry = New-Object System.Windows.Forms.ToolTip +$toolPasswordExpiry.SetToolTip($textDaysSincePassword, "Passwords expire after 90 days.") -# Search Button Click Event -$buttonSearch.Add_Click({ - $UserInfo = Get-ADUserInfo -SamAccountName $textUser.Text - if ($UserInfo) { - foreach ($field in $fields + $fieldsBool1 + $fieldsBool2) { - $textBoxes[$field].Text = $UserInfo.$field +#endregion + +#region Take action on accounts + +$tableLayout.RowCount++ +$accountActions = [ordered]@{ + Unlock = New-Object System.Windows.Forms.Button -Property @{Text = "Unlock Account" } + ResetPassword = New-Object System.Windows.Forms.Button -Property @{Text = "Reset Password" } + EmailUser = New-Object System.Windows.Forms.Button -Property @{Text = "Email User" } + CallUser = New-Object System.Windows.Forms.Button -Property @{Text = "Call User" } +} +$buttonFlow = New-Object System.Windows.Forms.FlowLayoutPanel +$buttonFlow.AutoSize = $true +$buttonFlow.WrapContents = $false +$buttonFlow.FlowDirection = [System.Windows.Forms.FlowDirection]::LeftToRight +foreach ($action in $accountActions.Keys) { + $accountActions[$action].AutoSize = $true + $buttonFlow.Controls.Add($accountActions[$action]) +} +$tableLayout.SetColumnSpan($buttonFlow, 6) +$tableLayout.Controls.Add($buttonFlow, 0, $tableLayout.RowCount - 1) + +#endregion + +#region Button Events + +# Click events for account actions +$accountActions['Unlock'].Add_Click({ + try { + if (-not ([System.Security.Principal.WindowsPrincipal][System.Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)) { + throw [System.AccessViolationException]::new("The current user is not an administrator or does not have access. Please try again as admin.") + } + $AccountUnlock = Get-ADUser -Identity $textBoxes['Username'].Text | Unlock-ADAccount -PassThru + $isAccountLocked = [bool]$AccountUnlock.LockedOut + if ($isAccountLocked) { + throw "Unhandled exception: Account not unlocked. Please contact Bailey." + } + else { + [System.Windows.Forms.MessageBox]::Show( + "$($AccountUnlock.SamAccountName) successfully unlocked!", + "Account Unlock Successful", + [System.Windows.Forms.MessageBoxButtons]::OK, + [System.Windows.Forms.MessageBoxIcon]::None + ) } } - else { - foreach ($field in $fields + $fieldsBool1 + $fieldsBool2) { - $textBoxes[$field].Text = "" + catch { + [System.Windows.Forms.MessageBox]::Show($_.ToString(), "Error", "OK", "Error") + } + }) + +$accountActions['ResetPassword'].Add_Click({ + #region Manager/User Prompt + $sendToForm = [System.Windows.Forms.Form]::new() + $sendToForm.Text = "Manager Or User" + $sendToForm.Size = [System.Drawing.Size]::new(300, 150) + $sendToForm.StartPosition = 'CenterParent' + $sendToForm.FormBorderStyle = 'FixedToolWindow' + + $lblPrompt = [System.Windows.Forms.Label]::new() + $lblPrompt.Text = "Send temporary password to manager or user?" + $lblPrompt.Location = [System.Drawing.Point]::new(10, 25) + $lblPrompt.Width = 280 + + $btnManager = [System.Windows.Forms.Button]::new() + $btnManager.Text = "Manager" + $btnManager.Location = [System.Drawing.Point]::new(50, 75) + $btnManager.Size = [System.Drawing.Size]::new(75, 25) + $btnManager.DialogResult = "OK" + + $btnUser = [System.Windows.Forms.Button]::new() + $btnUser.Text = "User" + $btnUser.Location = [System.Drawing.Point]::new(150, 75) + $btnUser.Size = [System.Drawing.Size]::new(75, 25) + $btnUser.DialogResult = "OK" + + $sendToForm.Controls.Add($lblPrompt) + $sendToForm.Controls.Add($btnManager) + $sendToForm.Controls.Add($btnUser) + $userButton = $sendToForm.ShowDialog() + #endregion + $userChoice = "" + + if ($userButton -eq [System.Windows.Forms.DialogResult]::OK) { + if ($sendToForm.ActiveControl -eq $btnManager) { + $userChoice = "Manager" + } + elseif ($sendToForm.ActiveControl -eq $btnUser) { + $userChoice = "User" + } + else { + return + } + } + + . $PSScriptRoot\..\Passphrase.ps1 + Get-ADUser -Identity $textBoxes['Username'].Text | Reset-ADUserPassword -SendTo $userChoice + }) + +$accountActions['EmailUser'].Add_Click({ + $email = $textBoxes['Mail'].Text + try { + $email = [mailaddress]$email + } + catch [System.ArgumentException], [System.Management.Automation.PSInvalidCastException] { + # Try using a potential address in the info field + $email = $textBoxes['Info'].Text + try { + $email = [mailaddress]$email + } + catch [System.ArgumentException], [System.Management.Automation.PSInvalidCastException] { + $email = $null } } + if ($null -eq $email) { + [System.Windows.Forms.MessageBox]::Show("No valid email address found for this user.", "Email Address Not Found", "OK", "Error") + } + else { + Start-Process "mailto:$($email.Address)" + } + }) + +$accountActions['CallUser'].Add_Click({ + $phone = [int]$textBoxes['IPPhone'].Text + if ($phone -le 0 -or $phone -gt 9999999) { + [System.Windows.Forms.MessageBox]::Show("Internal phone extension is either missing or not valid.", "Error", "OK", "Error") + } + else { + $telURI = "tel:$phone" + Start-Process $telURI + } }) +$setFieldValues = { + $form.ActiveControl = $null + $UserInfo = Get-ADUserInfo -SamAccountName $textUser.Text + Write-Host ([bool]$UserInfo) + if ($UserInfo) { + foreach ($field in $fields) { + $textBoxes[$field].Text = $UserInfo.$field + } + } + else { + foreach ($field in $fields) { + $textBoxes[$field].Text = "" + } + } +} + +# Search Button Click Event +$buttonSearch.Add_Click($setFieldValues) + + # Pressing 'Enter' will perform search action # $textUser.Add_KeyDown({ # if ($_.KeyCode -eq [System.Windows.Forms.Keys]::Enter) { @@ -173,5 +336,11 @@ $buttonSearch.Add_Click({ # } # }) +#endregion +if ($Username) { + $textUser.Text = $Username + $setFieldValues.Invoke() +} + # Show Form $form.ShowDialog()