List and count users that never logged on to domain


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.


#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

Complete network-setup on ESX host with vSphere powerCLI


Me and my colleague Stefan Lozancic had the task to configure the networks on our new Vsphere esx hosts. It was 14 hosts and 54 vlans, 1 vmotion and 1 management-network on each host that had to be configured. We used vSphere powerCLI to do it automated. First we populated a csv-file with all the vlans from one of our old hosts.

#Export Vlan from an esx host
Get-VirtualPortGroup * | Where-Object {$_.vmhostid -like "HostSystem-host-1555" -and $ -like "*vlan*"} | select vlanid,name | Export-Csv c:\temp\vlan2.csv -NoTypeInformation -NoClobber

After that we rebuild the vmotion and production network from scratch and populated the production network with the vlans from the csv. Since the hosts where prepared by two different person some hosts had the management network cards in an active/passive mode, so we made a check and changed those to active/active.

#NAME: CreateHostNetwork.ps1
#AUTHOR: Viktor Lindström and Stefan Lozancic
#COMMENTS: A script we used to stage our network
#setup on our Vspehre hosts
#Deletes default vm network.
$portremove = Get-VirtualPortGroup -name "VM Network"
Remove-VirtualPortGroup -VirtualPortGroup $portremove -Confirm:$false

#Put all nics in "management network" in active mode.
$passivenic = Get-NicTeamingPolicy -VirtualSwitch vswitch0 | where standbynic -NotLike $null
Get-NicTeamingPolicy -VirtualSwitch vswitch0 | Set-NicTeamingPolicy -MakeNicActive ($passivenic).StandbyNic

#Create new virtual switch for vmotion network
New-VirtualSwitch -name vSwitch1 -nic vmnic1,vmnic3 

#Create new virtual port group for vmotion
$ip = Read-Host "which IP for vmotion "
New-VMHostNetworkAdapter -PortGroup Vmotion -VirtualSwitch vSwitch1 -IP $ip -SubnetMask -VMotionEnabled:$true

#Create new virtual swtch for production networkn network
New-VirtualSwitch -name vSwitch2 -nic vmnic4,vmnic5 -NumPorts 256

#Create All Vlans for production 
$Import=Import-Csv C:\temp\vlan2.csv
    foreach ($nat in $Import)
    New-VirtualPortGroup -Name $nat.Name -VirtualSwitch vswitch2 -VLanId $nat.VLanId

Bulk change password at next logon


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 $ -ChangePasswordAtLogon $true
write-host $    

Create quota templates

Last year I was involved in a project where the goal was to migrate the users home directories from an old Windows 2003 server to a new Windows 2012 and going from no quotas to 30 different quotas. In the POC I created this script to setup the quota templates with warning messages and thresholds, and I am glad i did since the project changed the template size and the body in the email a couple of times.

#NAME: CreateQuotaTemplate.ps1 
#AUTHOR: Viktor Lindström
#COMMENTS: Write the quotas that are to be created in the $G 
#variable, for exaple if you write 1,2,3 it creates templates
#with 1GB, 2GB and 3GB, if you write 1..24 it will create 24 
#templates etc etc... It also creates two thresholds with
#mail action to the user. 
$GB = 1..24

foreach ($a in $gb) 
#Create action
    $Action= New-FsrmAction Email -mailto "[Source File Owner Email]" -Subject "[Quota Threshold]% av kvotan i din hemkatalog är uppnådd." -Body "Hej Du har överskridit [Quota Threshold]% av kvotabegränsningen i din hemkatalog. Tilldelad kvot är [Quota Limit MB] MB, och för tillfället används [Quota Used MB] MB ([Quota Used Percent]% över gränsen)."
#Create thresholds
        $Threshold = New-FsrmQuotaThreshold -Percentage 80 -action $Action
        $Threshold2 = New-FsrmQuotaThreshold -Percentage 95 -action $Action
#Create quota, shage the two GB to MB if you what megabytes instead of gigabytes    
        $Namn = ("$a" + "GB")
            New-FsrmQuotaTemplate -name $Namn -size ([int64]($a) * [int64]1GB) -Threshold $Threshold,$Threshold2


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"
foreach ($user in $users)
{Add-ADGroupMember -Identity "$group" -Members $}

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

$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