First help desk GUI tool

helpdeskDelivered my first GUI tool to our help desk today. They needed a tool to find out which users populated distribution groups and they also wanted to be able to export three different attributes to a csv. I did the GUI design in visual studio and used XAML because it looks a little nicer then the old windows forms. the application got real-time check against the Active directory as you type to check if the group exist and it doesn´t enable the list user(Lista användare) button until you type the name of a group that exist. When the listing is done you can choose which attributes to export. This is a 1.0 and it doesn’t handle nested groups, if they want that functionality or some other functionality in the future I will update this post.

 

<#

.SYNOPSIS

Få reda på och exportera vilka medlemmar en AD-grupp har.



.DESCRIPTION

Kör skriptet och fyll grupp, applikationen kollar så att gruppen finns i AD:et annars går det inte att söka. Vid export bockar man i vilka attribut 
man vill exportera och trycker på exportknappen, det skapas då en fil under c:\temp som heter resultat[timme.minut.sekund].csv tex c:\temp\resultat10.30.21.csv.

.NOTES
Made by: Viktor Lindström
http://powerhell.nu
Version 1.0 fyll på med förändringar här under.
#>

#build GUI

[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')

[xml]$XAML = @'

<Window 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Medlemmar i AD-grupp" Height="350" Width="687.807">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="258*"/>
            <ColumnDefinition Width="259*"/>
        </Grid.ColumnDefinitions>
        <TextBox Name="textBox" HorizontalAlignment="Left" Height="23" Margin="99,28,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="230"/>
        <Label Name="LabelGruppnamn" Content="Gruppnamn:" HorizontalAlignment="Left" Margin="10,25,0,0" VerticalAlignment="Top" Width="76" RenderTransformOrigin="0.005,0.483"/>
        <ListBox Name="ListboxResult" Grid.Column="1" HorizontalAlignment="Left" Height="202" Margin="32,70,0,0" VerticalAlignment="Top" Width="279"/>
        <Button Name="ButtonSearch" Content="Lista användare" HorizontalAlignment="Left" Margin="99,70,0,0" VerticalAlignment="Top" Width="230" Height="35"/>
        <Label Name="LabelAnvändare" Content="Användare i gruppen:" Grid.Column="1" HorizontalAlignment="Left" Margin="185,25,0,0" VerticalAlignment="Top" Width="126"/>
        <CheckBox Name="checkBoxAnvändarnamn" Content="Användarnamn" HorizontalAlignment="Left" Margin="99,143,0,0" VerticalAlignment="Top" Width="240"/>
        <CheckBox Name="checkBoxNamn" Content="Namn" HorizontalAlignment="Left" Margin="99,169,0,0" VerticalAlignment="Top" Width="240"/>
        <CheckBox Name="checkBoxMail" Content="E-mailadress" HorizontalAlignment="Left" Margin="99,195,0,0" VerticalAlignment="Top" Width="240"/>
        <Label Name="labelExport" Content="Vad ska exporteras?" HorizontalAlignment="Left" Margin="10,117,0,0" VerticalAlignment="Top" Width="116"/>
        <Button Name="buttonExport" Content="Exportera" HorizontalAlignment="Left" Margin="99,230,0,0" VerticalAlignment="Top" Width="230" Height="31"/>
        <CheckBox Name="checkboxGruppnamn" Content="Grupp finns?" Grid.Column="1" HorizontalAlignment="Left" Margin="32,31,0,0" VerticalAlignment="Top"/>
        <Label Name="labelExport1" Content="" HorizontalAlignment="Left" Margin="10,279,0,0" VerticalAlignment="Top" Width="319"/>

    </Grid>
</Window>


'@

$reader=(New-Object System.Xml.XmlNodeReader $xaml) 
try{$Form=[Windows.Markup.XamlReader]::Load( $reader )}
catch{Write-Host "Unable to load Windows.Markup.XamlReader. Some possible causes for this problem include: .NET Framework is missing PowerShell must be launched with PowerShell -sta, invalid XAML code was encountered."; exit}
$xaml.SelectNodes("//*[@Name]") | foreach {Set-Variable -Name ($_.Name) -Value $Form.FindName($_.Name)}

# Global variable for result
$resultArray = @()

# Disable button by default
$ButtonSearch.IsEnabled = $false


# Funtion to test if AD-group exists.
function Test-Group 
{

if ((Get-ADGroup -Filter {SamAccountName -eq $textBox.Text}) -ne $null)
{$checkboxGruppnamn.IsChecked = $true
  $ButtonSearch.IsEnabled = $true} else {$checkboxGruppnamn.IsChecked = $false
  $ButtonSearch.IsEnabled = $false}
    }

# Searchbutton, gets all memebers of the group specified in the textbox, puts result in $resultarray
$ButtonSearch.add_click({
    $script:resultArray = @()
    $ListboxResult.Items.Clear()
    $allMembers = Get-ADGroupMember -Identity $textBox.Text
    $members = $allMembers | Where-Object {$_.objectClass -eq "user"}
    $groups = $allMembers | Where-Object {$_.objectClass -eq "group"}

    
        foreach ($item in $members)
        {
         $member = Get-ADObject -Identity $item -Properties mail, displayname, samaccountname | Select-Object samaccountname, mail, displayname
         $ListboxResult.Items.Add($member.displayname)
         $script:resultArray += $member
        }
          foreach ($group in $groups)
          {
              $ListboxResult.Items.Add($group.name)
              $script:resultArray += $group | Select-Object name
          }
                        })

# Exportbutton, exports attributes that has been checked in the checkboxes, exports to an CSV-file c:\temp\resultat[HH.mm.ss].csv to uniq it.
                $buttonExport.add_click({
                $export = @()
                
                $date = get-date -Format HH.mm.ss
                $exportdate =  "c:\temp\resultat$date.csv"
                if (Test-Path $exportdate) {Remove-Item $exportdate}

                    foreach ($object in $resultArray)
                    {
                     $export += New-Object psobject -Property @{
               
                      "Användarnamn" = if ($checkBoxAnvändarnamn.IsChecked -eq $true) {$object.samaccountname};
                      "Namn" = if ($checkBoxNamn.IsChecked -eq $true) {$object.displayname};
                      "E-mailadress" = if ($checkBoxMail.IsChecked -eq $true) {$object.mail};
                    }
                    }

                    $export | Export-Csv $exportdate -NoTypeInformation -Encoding UTF8 -Delimiter ";"
                    $labelExport1.Content = "Export klar, filen hittar du här: $exportdate"
                    

                    
                 })
# Runs the AD-test group function in realtime as you write in the textbox.
$textBox.add_Keyup({ 
    
    Test-Group
})

$Form.ShowDialog() | out-null

Collect users with a certain attribute and clear the attribute.

Last week a college working with identity management needed a script to clear a dummy AD-attribute. All users that don´t have a telephone number needed a dummy phone number because of an external calendar system. This script collects all users with the telephoneNumber attribute 99999 in an variable and then exports the users in the variable with all their attributes before it clears the telephoneNumber attribute. We use it as an scheduled task.

Import-Module Activedirectory
# get date and time tog get the backup unique.
$date = get-date -Format yyyymmddHHmm
# Samla in användare som har 99999 som telefonnummer
# Collect users that hav 99999 as telephonenumber attribute.
$users = Get-ADUser -filter 'telephoneNumber -like "99999"' -Properties *

# Check if backup-file exists, if it exists stop the script and alert the usr, if it not exists export all users that is about to get the attribute changed.
if (Test-Path c:\temp\backup_$date.txt)
{Write-Host  "vänta en minut backupfilen finns redan" -BackgroundColor Yellow -ForegroundColor Red
    
}

else
{
Write-Host "exporterar användare" -BackgroundColor Black -ForegroundColor White
$users | Export-Csv c:\temp\backup_$date.txt -Encoding UTF8 -NoTypeInformation

foreach ($user in $users)
{
Write-Host "Clearing attribute on $user"
  Set-ADUser -Identity $user -Clear telephoneNumber
}
} 

Bulk modify AD users from CSV

The last post showed how to create AD users from CSV, here is how to bulk modify attributes from CSV

#Modify AD user from CSV file, in this case i Change the extensionAttribute1 and extensionAtribute2
#anvandare,test,Url
#viklin,test1,https://www.contoso.com
#tonrim,test2,https://www.contoso.com
#steloz,test3,https://www.contoso.com
$Import=Import-Csv C:\temp\csv.txt
    foreach($user1 in $Import)
        {
    set-aduser $user1.anvandare -Replace @{extensionAttribute1=$user1.test; extensionAttribute2=$user1.Url} 
    }

Bulk create AD users from CSV

In a Facebook group a user asked for a script to create users from CSV, it is very easy:

# $sourceuser store the the user you whant to create users from in an variable
# $import imports CSV in an variable with the users the scv looks like this:
# 
# logon,FirsName,LastName,DisplayName
# klitom,Tommy,Stenstrom,Stenstrom Tommy
# klidoo,Sonny,Ramos,Ramos Sonny
# klikri,Conny,Edwards,Edwards Conny
#
# $ou specifies wich OU you whant to put the users in. 
$sourceuser = get-aduser klidan
$import = import-csv C:\temp\användare.txt
$ou = "OU=Admin,OU=Data,DC=adm,DC=contoso,DC=se"
foreach ($användare in $import)
{

New-ADUser -SamAccountName $användare.logon -UserPrincipalName $användare.logon -Name $användare.DisplayName -GivenName $användare.FirstName -Surname $användare.LastName -DisplayName $användare.DisplayName  -Instance $sourceuser -Enabled $true -path $ou -AccountPassword (Read-Host -AsSecureString "AccountPassword") -ChangePasswordAtLogon $true }

List and count users that never logged on to domain

neverloggedin

I got an urgent case from the boss, we had to compare a list of users from our meta-catalog with users in our AD and list and count which users who never logged on to domain. I imported the csv in an variable and then used an foreach-loop to check if the users had logged in or not. We also wanted to list and count all users that where included in the csv-file but not in the active driectory, I used the ErrorVariable to do that and the appended each entry to a text-file with the out-file append switch. As you can see I used two different techniques to export multiple data from the foreach-loop. The first one when I exported the users that hadn´t logged on, where I first created an variable with an empty array  “$users = @()” , then instead of running the command to get the users I used the + to fill the array with result “$users +=”, on the second I used the out-file as I explained above.  When the lists where done I used the count and length property.

 

#--------------------------------------------------------------------
#NAME:UsersNeverLogon.ps1
#AUTHOR: Viktor Lindström
#
#COMMENTS: List and count users accounts that never loged on.
#It also lists and counts users that exist in our meta-catalog but
#not in our Active directory
#--------------------------------------------------------------------

#Import from CSV that contains usesrs samaccountname under header accountname.
$import = Import-Csv "C:\temp\acc.txt"

#Creates an empty array
$users = @()

#foreach loop to check all users.
foreach ($anv in $import)
{
#Checks if user dont have the lastLogonTimestamp-attribute set, and if it isn´t set it appends users samaccountname in the array. If the user dosn´t exist in the AD it puts one error code-line in an variable.
$users += get-aduser $anv.accountName -ErrorAction SilentlyContinue -ErrorVariable err | Get-ADObject -Properties samaccountname,"lastLogonTimestamp" | where "lastLogonTimestamp" -eq $null | select samaccountname 
$err | Out-File -FilePath "C:\temp\users_not_in_AD.txt" -Append
}
#Export users to CSV and counts the users.
$users | export-csv -Path c:\temp\users_never_logged_in.txt -NoTypeInformation
Write-Host Number of users who have never logged in: $users.count
$dontexist = Get-Content C:\temp\users_not_in_AD.txt
Write-Host Number of users that are not in active directory $dontexist.Length

Bulk change password at next logon

heartbleed

Because one of our services that are exposed to the internet had the famous Heartbleed bug we had to do a bulk change password at next logon for 1100 users. A pretty easy task (maby to easy for this blog?) but since it´s smoking hot and one of my colleges (let`s call him J.B) asked if I could post the script on the blog, here it is. First I collected all the users in a csv-file, then I imported the csv-file and put the content in an foreach loop and changed the ChangePasswordAtLogon attribute to true. I am not sure if picking the cn attribute is correct but set-ADUser says -Identity should be “LDAP display name” and 5 seconds of sloppy googling I got an answer that cn equels LDAP display name, but I got some errors when setting the attribute in the second script som it might be better to pick sam account name.

Get-ADGroupMember "group name" | where objectclass -eq user | get-adobject -properties * | select cn | export-csv C:\temp\users.txt -NoTypeInformation -Encoding Unicode
$Import = Import-Csv C:\temp\users.txt

foreach ($user in $import)
{
Set-ADUser -Identity $user.cn -ChangePasswordAtLogon $true
write-host $user.cn    
}

Populate AD Group from profile

Today we needed to collect all the users who had logged in the last 90 days on one of our remote desktop servers. This script looks at the user profile directories last write time to determine last login and then put all users who has logged in last 90 days in an array. After that it creates a new AD-group and populates the group with the users from the array.

#-------------------------------------------------------------
#NAME: PopulateAdGroupFromProfile.ps1 
#AUTHOR: Viktor Lindström
#
#COMMENTS: This script fetch users who logged in the last 90 days,
#and the creates a securitygroup and put all the users in that group.
#-------------------------------------------------------------
#Get users who have used the server last 90 days
$date= (get-date).AddDays(-90)
$users = Get-ChildItem J:\Users | where LastWriteTime -GT $date
$count = $users.Count
Write-Host "Det är $count stycken användare som använt fjärrskrivbordet senaste 90 dagarna"

#Create new AD group
$group = "BG Fjärrskrivbord"
New-ADGroup -Name "$group" -GroupCategory Security -GroupScope Global -path "OU=Global,DC=contoso,DC=com" -Description "Behörighetsgrupp för användare som ska använa fjärrskrivbordet på srv-xxxxxxxx"

# check if group is created, and if it is populate group with the users who have used the server last 90 days
$adgrupp = $null
$adgrupp = Get-ADGroup $group

if ($adgrupp -eq $null)
{Write-Host "Group does not exist"
    }
else
{
foreach ($user in $users)
{Add-ADGroupMember -Identity "$group" -Members $user.name}
}

Count AD group members

Every year we have to count and report licenses on different systems. Since we use centralized Active Directory security groups to decide which users who gain access to RDS servers etc etc… it`s a pretty easy task to count the users in those groups to find out how many CALs we need. When the boss interrupts you more then once it´s time to use powershell to solve it. This script include one level nested groups.

#-------------------------------------------------------------
#NAME: CountAdGroupMembers.ps1
#AUTHOR: Viktor Lindström
#
#COMMENTS: This script counts and summary members i multiple AD groups.
#It also includes one level nested groups
#-------------------------------------------------------------
function count-members
{
param(
[parameter(mandatory)]
[array]$grupper)

$sum = 0

foreach ($grupp1 in $grupper)
{$grupper3 = Get-ADGroupMember $grupp1 | Where objectclass -eq "group"
$grupper += $grupper3
}

foreach ($grupp in $grupper)
{$count = Get-ADGroupMember $grupp | Where objectclass -eq "User"
$sum += $count.count
}
$sum
}