Set-ADPassword.ps1

<#PSScriptInfo
 
.VERSION 1.0
 
.GUID 4111a7cc-46b4-4648-8b8b-e7743bd61b86
 
.AUTHOR Juan Granados
 
.COPYRIGHT 2021 Juan Granados
 
.TAGS AD Active Directory Reset Password GUI
 
.LICENSEURI https://raw.githubusercontent.com/juangranados/powershell-scripts/main/LICENSE
 
.PROJECTURI https://github.com/juangranados/powershell-scripts/tree/main/GUI%20Password%20Reset%20Tool%20for%20Active%20Directory
 
.RELEASENOTES
    Initial release
 
#>


<#
.DESCRIPTION
    Powershell script for IT support team which allow to reset AD users password in a GUI interface.
    Requirements:
        - PowerShell 4 (Windows Management Framework 4) o highter.
        - Support users must be able to reset AD users password:
            https://community.spiceworks.com/how_to/1464-how-to-delegate-password-reset-permissions-for-your-it-staff
        - Support computers must install RSAT (Remote Server Administration Tools):
            dism /Add-Capability /CapabilityName:$((Get-WindowsCapability -Online -Name "*Rsat.ActiveDirectory*").Name) /Online
    .NOTES
    Author: Juan Granados
    Thanks to: https://foxdeploy.com/2015/04/10/part-i-creating-powershell-guis-in-minutes-using-visual-studio-a-new-hope/
#>

$inputXML = @"
<Window x:Name="Password Reset Tool" x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Password Reset Tool" Height="283" Width="284"
    ResizeMode="NoResize" WindowStartupLocation="CenterScreen"
    FocusManager.FocusedElement="{Binding ElementName=TextBoxUser}">
    <Grid Margin="-2,-23,-6,-3" HorizontalAlignment="Left" Width="286">
        <Label x:Name="LabelTitle" Content="Password Reset Tool" HorizontalAlignment="Center" Height="33" Margin="31,33,0,0" VerticalAlignment="Top" Width="180" FontSize="15" Grid.ColumnSpan="2"/>
        <Label x:Name="LabelUser" Content="User" HorizontalAlignment="Left" Margin="15,79,0,0" VerticalAlignment="Top" Height="23" Width="83"/>
        <Label x:Name="LabelPass" Content="Password" HorizontalAlignment="Left" Margin="13,118,0,0" VerticalAlignment="Top" Height="23" Width="83"/>
        <TextBox x:Name="TextBoxUser" HorizontalAlignment="Left" Height="21" Margin="91,81,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="147" ToolTip="User account name" TabIndex="1" Grid.ColumnSpan="2"/>
        <CheckBox x:Name="CheckBoxChangePass" Content="Change password &#xD;&#xA;at next logon" HorizontalAlignment="Left" Height="33" Margin="91,159,0,0" VerticalAlignment="Top" Width="161" TabIndex="3"/>
        <PasswordBox x:Name="TextBoxPass" HorizontalAlignment="Left" Margin="91,117,0,0" VerticalAlignment="Top" Width="147" Height="21" ToolTip="User new password" TabIndex="2" Grid.ColumnSpan="2"/>
        <Button x:Name="ButtonOK" Content="OK" HorizontalAlignment="Center" Margin="47,0,167,18" Width="72" RenderTransformOrigin="0.5,0.5" Height="28" TabIndex="4" IsDefault="True" VerticalAlignment="Bottom">
            <Button.RenderTransform>
                <TransformGroup>
                    <ScaleTransform/>
                    <SkewTransform/>
                    <RotateTransform Angle="360.162"/>
                    <TranslateTransform/>
                </TransformGroup>
            </Button.RenderTransform>
        </Button>
        <Button x:Name="ButtonExit" Content="Exit" Margin="167,0,47,18" Width="72" RenderTransformOrigin="0.5,0.5" Height="28" TabIndex="5" IsCancel="True" HorizontalAlignment="Center" VerticalAlignment="Bottom">
            <Button.RenderTransform>
                <TransformGroup>
                    <ScaleTransform/>
                    <SkewTransform/>
                    <RotateTransform Angle="360.162"/>
                    <TranslateTransform/>
                </TransformGroup>
            </Button.RenderTransform>
        </Button>
        <CheckBox x:Name="CheckBoxEnable" Content="Unlock account" HorizontalAlignment="Left" Height="21" Margin="91,197,0,0" VerticalAlignment="Top" Width="150" TabIndex="3"/>
    </Grid>
</Window>
"@
       
 
$inputXML = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N'  -replace '^<Win.*', '<Window'
 
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$XAML = $inputXML

#Read XAML
$reader=(New-Object System.Xml.XmlNodeReader $xaml) 
try{$Form=[Windows.Markup.XamlReader]::Load( $reader )}
catch{Write-Host "Unable to load Windows.Markup.XamlReader. Double-check syntax and ensure .net is installed."}

#===========================================================================
# Load XAML Objects In PowerShell
#===========================================================================
 
$xaml.SelectNodes("//*[@Name]") | %{Set-Variable -Name "WPF$($_.Name)" -Value $Form.FindName($_.Name)}
 
Function Get-FormVariables{
if ($global:ReadmeDisplay -ne $true){Write-host "If you need to reference this display again, run Get-FormVariables" -ForegroundColor Yellow;$global:ReadmeDisplay=$true}
write-host "Found the following interactable elements from our form" -ForegroundColor Cyan
get-variable WPF*
}
 
#===========================================================================
# Funciones
#===========================================================================

#Get-FormVariables

$WPFButtonOK.Add_Click({
    try{
        if ([string]::IsNullOrEmpty($WPFTextBoxUser.Text)){
            $Message="Error. User name is empty."
        }
        elseif ([string]::IsNullOrEmpty($WPFTextBoxPass.Password)-and ($WPFCheckBoxEnable.IsChecked -eq $false) ){
            $Message="Error. Password is empty."
        }
        else{
            if (![string]::IsNullOrEmpty($WPFTextBoxPass.Password)){
                $AccountPassword = (ConvertTo-SecureString $WPFTextBoxPass.Password -AsPlainText -Force)
                if ($WPFCheckBoxChangePass.IsChecked){
                Set-ADAccountPassword $WPFTextBoxUser.Text -NewPassword $AccountPassword -Reset -PassThru | Set-ADuser -ChangePasswordAtLogon $True
                }
                else{
                    Set-ADAccountPassword $WPFTextBoxUser.Text -NewPassword $AccountPassword -Reset -PassThru
                }
                $Message="Password changed"
                if ($WPFCheckBoxEnable.IsChecked){
                    Enable-ADAccount -Identity $WPFTextBoxUser.Text
                    $Message+=". User account unlocked"
                }
            }
            elseif ($WPFCheckBoxEnable.IsChecked){
                Enable-ADAccount -Identity $WPFTextBoxUser.Text
                $Message+="User account unlocked"
            }
        }
        Write-Host "$Message" -ForegroundColor Cyan
    }catch{
        Write-Host "Error setting user properties" -ForegroundColor Red
        Write-Host "Exception Type: $($_.Exception.GetType().FullName)" -ForegroundColor Red
        Write-Host "Error Message: $($_.Exception.Message)" -ForegroundColor Red
        $Message="An error has ocurred: "+$($_.Exception.Message)
    }
    [System.Windows.Forms.MessageBox]::Show("$Message")
})

$WPFButtonExit.Add_Click({
    $Form.Close()
})

# Function to check for Module Dependencies
Function Get-MyModule
{
    Param([string]$name)
    if(-not(Get-Module -name $name))
    {
    if(Get-Module -ListAvailable |
    Where-Object { $_.name -eq $name })
    {
    Import-Module -Name $name
    $true
    } #end if module available then import
    else { $false } #module not available
    } # end if not module
    else { $true } #module already loaded
} #end function get-MyModule

#===========================================================================
# Shows the form
#===========================================================================
Write-Host "Loading required modules..."
If(! (Get-MyModule â€“name "ActiveDirectory")){
    $command = 'dism /Add-Capability /CapabilityName:$((Get-WindowsCapability -Online -Name "*Rsat.ActiveDirectory*").Name) /Online'
    [System.Windows.Forms.MessageBox]::Show("Error loading Active Directory Module for Windows Powershell. Please install RSAT running: $command")
    Exit
}
Import-Module ActiveDirectory
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | out-null
$Form.ShowDialog() | out-null