Menu

Virtual Geek

Tales from real IT system administrators world and non-production environment

PowerShell GUI: Copy group membership from one user to another user in Active Directory

This is a GUI part of my earlier written script PowerShell: Copy group membership from one user to another user in Active Directory. I converted same script to GUI written in WPF language for simplifying task. It requires Source User and Destination users list is loaded from text file. (Text file contains list of users), Logs can be seen on side pane.

powershell wpf gui copy ad user group membership source groups list, domain admins, enterprise admins, schema admins administrators copy clone groups membership from one user to another users member of.png

Logs can be seen on console as well, It is exact log copy of my earlier script.

powershell wpf gui copy ad user group membership source groups list, domain admins, group policy, schema admins administrators copy groups membership from one user to another users member of user prop.png

This script is available on Github.com, It can also be downloaded from here.

<#  
    .Synopsis  
    Copy or clone source user's member of group to another user, Copy group membership from one user to another in Active Directory.
    .Description  
    Run this script on domain controller, or install RSAT tool on your client machine. This will copy existing given users group to other give group. It validates and verify whether Source and Destination users exists or you have access.
    .Example  
    .\Copy-AdGroupMemberShip.ps1 -SourceUserGroup Administrator -DestinationUsers user1, user2, user3
        
    It takes provided Source user, note down which groups it is member of. Add same groups in the member of tabs of users list provided in parameter DestinationUsers.
    .Example
    .\Copy-AdGroupMemberShip.ps1 -SourceUser Administrator -DestinationUsers (Get-Content C:\Userlist.txt)

    Users list can be provided into text file.
    .Example
    user1, user2, user3 | .\Copy-AdGroupMemberShip.ps1 -SourceUser Administrator

    .Notes
    NAME: Copy-AdGroupMemberShipGui
    AUTHOR: Kunal Udapi
    CREATIONDATE: 5 February 2019
    LASTEDIT: 6 February 2019
    KEYWORDS: Copy or clone source user's member of group to another user.
    .Link  
    #Check Online version: http://kunaludapi.blogspot.com
    #Check Online version: http://vcloud-lab.com
    #Requires -Version 3.0  
    #>  
   ########################################################################  
   # Generated On: 5 February 2019  
   # Generated By: vCloud-lab.com  
   # Tested On: Windows 10  
   # For any question drop an question
   ########################################################################  

   #requires -Version 3 

   #Load required libraries
   Add-Type -AssemblyName PresentationFramework, PresentationCore, WindowsBase, System.Windows.Forms, System.Drawing, System.Windows.Forms

   function Show-MessageBox {   
    param (   
      [string]$Message = "Show user friendly Text Message",   
      [string]$Title = 'Title here',   
      [ValidateRange(0,5)]   
      [Int]$Button = 0,   
      [ValidateSet('None','Hand','Error','Stop','Question','Exclamation','Warning','Asterisk','Information')]   
      [string]$Icon = 'Error'   
    )   
    #Note: $Button is equl to [System.Enum]::GetNames([System.Windows.Forms.MessageBoxButtons])   
    #Note: $Icon is equl to [System.Enum]::GetNames([System.Windows.Forms.MessageBoxIcon])   
    $MessageIcon = [System.Windows.Forms.MessageBoxIcon]::$Icon   
    [System.Windows.Forms.MessageBox]::Show($Message,$Title,$Button,$MessageIcon)   
  }  

  Function Confirm-AD {  
    $AllModules = Get-Module -ListAvailable ActiveDirectory  
    if (!$AllModules) {  
        Show-MessageBox -Message 'Install RSAT tool or AD Management tools' -Title 'Missing Ad tools' -Icon Error | Out-Null
    }
    else {
      Import-Module ActiveDirectory
    }
    $progressBar.Value = 10
  }

  function Show-FileBrowser {
    $openFileBrowser = New-Object System.Windows.Forms.OpenFileDialog
    $openFileBrowser.Title = 'Open txt file with users list'
    $openFileBrowser.InitialDirectory = 'C:\' #[Environment]::GetFolderPath('SystemDrive') 
    #$openFileBrowser.CheckFileExists = $true
    $openFileBrowser.CheckPathExists = $true
    $openFileBrowser.Filter =  "Text files (*.txt)|*.txt|All files (*.*)|*.*" #'Documents (*.docx)|*.docx|SpreadSheet (*.xlsx)|*.xlsx'
    $null = $OpenFileBrowser.ShowDialog()
    
    $openFileBrowser.FileName
    $progressBar.Value = 20
  }

[xml]$xaml = @"
<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApp2"

    Title="Copy AD user group membership - Launch as Administrator" Height="245" Width="800" ResizeMode="NoResize">
<Grid>
    <TextBlock x:Name="textBlockSourceUser" HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" Text="Source user:" VerticalAlignment="Top"/>
    <TextBox x:Name="textBoxSourceUser" HorizontalAlignment="Left" Height="23" Margin="79,9,0,0" TextWrapping="Wrap" Text="Administrator" VerticalAlignment="Top" Width="165" Background="LightCoral"/>
    <Button x:Name="buttonSourceGroupList" Content="Source Groups List" HorizontalAlignment="Left" Margin="130,37,0,0" VerticalAlignment="Top" Width="114" Height="23"/>
    <ListBox x:Name="listBoxSourceUserGroups" HorizontalAlignment="Left" Margin="10,65,0,0" Width="234" Height="87" VerticalAlignment="Top" Background="KHAKI"/>
    <TextBlock x:Name="textBlockDestinationUsers" HorizontalAlignment="Left" Margin="249,10,0,0" TextWrapping="Wrap" Text="Destination Users list:" VerticalAlignment="Top"/>
    <TextBox x:Name="textBoxDestinationUsersList" Height="95" Margin="249,37,307,0" TextWrapping="Wrap" Text="Load List from txt file" VerticalAlignment="Top" AcceptsReturn="True" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" IsReadOnly='True' Background="KHAKI"/>
    <Button x:Name="buttonVerifyUserList" Content="Verify Users in AD" Margin="357,0,307,59" VerticalAlignment="Bottom" Height="23" IsEnabled="False"/>
    <Button x:Name="buttonLoadFromTxt" Content="Load from TXT" Margin="389,10,307,0" VerticalAlignment="Top" Height="23" IsEnabled='False'/>
    <Button x:Name="buttonCopyMemberGroups" Content="Copy-AdMemberShip" Margin="357,0,307,22" VerticalAlignment="Bottom" Height="23" IsEnabled="False"/>
    <ProgressBar x:Name="progressBar" Height="23" Margin="140,0,0,22" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="212"/>
    <Label x:Name="webSite" Content="http://vcloud-lab.com" HorizontalAlignment="Left" Margin="10,0,0,19" VerticalAlignment="Bottom" Foreground="Blue" ToolTip="http://vcloud-lab.com"/>
    <TextBox x:Name="textBoxLogs" HorizontalAlignment="Right" Margin="0,10,10,22" TextWrapping="Wrap" Text="Logs" Width="292" IsReadOnly="True" Background="DARKKHAKI" VerticalScrollBarVisibility="Visible"/>

</Grid>
</Window>
"@

#Read the form
$Reader = (New-Object System.Xml.XmlNodeReader $xaml) 
$Form = [Windows.Markup.XamlReader]::Load($reader) 

#AutoFind all controls
$xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]")  | ForEach-Object { 
New-Variable  -Name $_.Name -Value $Form.FindName($_.Name) -Force 
}

#Website url
#$uri = {[system.Diagnostics.Process]::start('http://vcloud-lab.com')}
#$webSite.Add_PreviewMouseDown($uri)
$webSite.Add_MouseLeftButtonUp({[system.Diagnostics.Process]::start('http://vcloud-lab.com')})
$webSite.Add_MouseEnter({$webSite.Foreground = 'Purple'})
$webSite.Add_MouseLeave({$webSite.Foreground = 'Blue'})

$buttonSourceGroupList.Add_Click({
    Confirm-AD
    $textBoxLogs.Text = "Verifying Source User '{0}' in AD" -f $textBoxSourceUser.Text
    try 
    {
        $Global:sourceUserMemberOf = Get-AdUser $textBoxSourceUser.Text -Properties MemberOf -ErrorAction Stop
        $listBoxSourceUserGroups.ItemsSource = $sourceUserMemberOf.MemberOf | ForEach-Object {(($_ -split 'CN=') -split ',')[1]}
        $buttonLoadFromTxt.IsEnabled = $true
        $textBoxLogs.Text = "{0}`nVerified user '{1}' exist in AD" -f $textBoxLogs.Text, $textBoxSourceUser.Text
    }
    catch 
    {
        Write-Host -BackgroundColor DarkRed -ForegroundColor White $Error[0].Exception.Message
        $textBoxLogs.Text = "{0}`nProvide valid user,'{1}' doesn't exist in AD" -f $textBoxLogs.Text, $textBoxSourceUser.Text
        #Break
    }
})

$buttonLoadFromTxt.Add_Click({
    $fileName = Show-FileBrowser
    $textBoxLogs.Text = "{0}`n==============================" -f $textBoxLogs.Text
    if (-not([System.String]::IsNullOrWhiteSpace($fileName))) { #[string]::IsNullOrEmpty($fileName)
        $Global:fileContents = Get-Content -Path $fileName 
        $listOfUsers = $fileContents | ForEach-Object {"`r`n$_"}
        #$textBoxDestinationUsersList.Text = $null
        $textBoxDestinationUsersList.Text = $listOfUsers[0..$listOfUsers.Length]
        $buttonVerifyUserList.IsEnabled = $true
        $textBoxLogs.Text = "{0}`nSelected file name '{1}'" -f $textBoxLogs.Text, $fileName
    }
    else {
        Write-Host 'Please select text file' -BackgroundColor DarkRed
        $textBoxLogs.Text = "{0}`nNo Text file selected" -f $textBoxLogs.Text
    }
})

$buttonVerifyUserList.Add_Click({
    $Global:confirmedUserList = @()
    $textBoxLogs.Text = "{0}`n==============================" -f $textBoxLogs.Text
    foreach ($user in ($textBoxDestinationUsersList.Text -split ' ').trim())
    {
        try 
        {
            $textBoxLogs.Text = "{0}`nChecking user '{1}' status in AD" -f $textBoxLogs.Text, $user
            Write-Host -BackgroundColor DarkGray "Checking user '$user' status in AD..." -NoNewline
            [void](Get-ADUser $user -ErrorAction Stop)
            Write-Host -BackgroundColor DarkGreen -ForegroundColor White "...Tested user '$user' exist in AD"
            $textBoxLogs.Text = "{0}`nTested user '{1}' exist in AD" -f $textBoxLogs.Text, $user
            $buttonCopyMemberGroups.IsEnabled = $true
            $Global:confirmedUserList += $user
        }
        catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
        {
            Write-Host -BackgroundColor DarkRed -ForegroundColor White "...User '$user' doesn't exist in AD"
            $textBoxLogs.Text = "{0}`nUser '{1}' doesn't exist in AD" -f $textBoxLogs.Text, $user
        } #catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
        catch 
        {
            Write-Host -BackgroundColor DarkRed -ForegroundColor White "...Check your access"
            $textBoxLogs.Text = "{0}`nCheck your access on user '{1}'" -f $textBoxLogs.Text, $user
        } #catch
    } #foreach ($user in $destinationUser)

    $textBoxDestinationUsersList.Text = $confirmedUserList | ForEach-Object {"`n$_"}
    $progressBar.Value = 50
})

$buttonCopyMemberGroups.Add_Click({
    $textBoxLogs.Text = "{0}`n==============================" -f $textBoxLogs.Text
    foreach ($group in $sourceUserMemberOf.MemberOf) 
    {
        try 
        {
            $Global:groupInfo = Get-AdGroup $group
            $groupName = $groupInfo.Name
            $groupInfo | Add-ADGroupMember -Members $confirmedUserList -ErrorAction Stop
            Write-Host -BackgroundColor DarkGreen "Added users to group '$groupName'"
            $textBoxLogs.Text = "{0}`nAdded users to group '{1}' " -f $textBoxLogs.Text, $groupName
        } #try

        catch
        {
            #$Error[0].Exception.GetType().fullname
            if ($null -eq $confirmedUserList[0]) {
                Write-Host -BackgroundColor DarkMagenta "Provided destination user list is invalid, Please Try again."
                $textBoxLogs.Text = "{0}`nProvided destination users list is invalid " -f $textBoxLogs.Text
                #break
            }
            Write-Host -BackgroundColor DarkMagenta $groupName - $($Error[0].Exception.Message)
            $textBoxLogs.Text = "{0}`n{1} - {2} " -f $textBoxLogs.Text, $groupName, $Error[0].Exception.Message
        } #catch
    } #foreach ($group in $sourceUserMemberOf.MemberOf)
    $progressBar.Value = 100
})

#Mandetory last line of every script to load form
[void]$Form.ShowDialog()

New update 16 March 2019
After receiving some good feebacks and ideas on this script, I revised complete script created new GUI and removed few bugs. It is available on Github.com, Version 2 can also be downloaded from here.

copy user membership from one user properties to another wpf gui powershell mahapps.metro

Useful Scripts
PowerShell Active Directory: Sync group membership from one user to another user and move to OU
Powershell Active Directory: Show treeview of nested Group members downstream hierarchy
Oneliner Microsoft Powershell Script Get members from a list of group from Active Directory in excel

Go Back



Comment

Blog Search

Page Views

2637666

Follow me on Blogarama