Category Archives: PowerShell

Modify Multiple Active Directory Accounts – PowerShell

The other day I wrote a script that populated my test server with 290 accounts. You can check it out HERE. Today I decided I would modify the logon hours for those accounts… It turned out to be more difficult than I thought because of the way you have to present the logon hours:

[byte[]]$hours = @(0,0,0,0,224,255,3,224,255,3,224,255,3,224,255,3,224,255,3,0,0)

There were a couple of sites that tried to explain it, but it easier to set the logon hours through the Active Directory Users and Computers MMC Snapin on a test user. Then go into ADSI Edit and take a look at the properties on the object and change the “Value Format” to Decimal:

ADSIEdit1

After running the script, the end result is 290 accounts in the Employees OU changed from the default 24/7 logon to the following:

ModHours

#Check if we are running in elevated powershell
If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`
    [Security.Principal.WindowsBuiltInRole] "Administrator"))
{
    Write-Warning "You do not have Administrator rights to run this script!`nPlease re-run this script as an Administrator!"
    Break
}

#Check if the Active Directory Module is loaded
if(-not (Get-Module ActiveDirectory)){
	Import-Module ActiveDirectory
}

#Grab the specific accounts we want(Everything in the Employees OU)
$employees = Get-ADUser -Filter * -SearchBase "OU=Employees,DC=lmnop,DC=local"

#Logon Hours Monday - Friday from 5AM - 6PM
#(I don't know how this works so I set it in MMC and check the value in ADSIEdit in Decimal)

[byte[]]$hours = @(0,0,0,0,224,255,3,224,255,3,224,255,3,224,255,3,224,255,3,0,0)

# create a hashtable to update the logon hours and a description
$replaceHashTable = New-Object HashTable
$replaceHashTable.Add("logonHours", $hours)
$replaceHashTable.Add("description", "Employees can only logon from Monday through Friday from 5:00 AM to 6:00 PM")

$count = 0

foreach($employee in $employees){
Write-Host "Changing logon hours for" $employee.SamAccountName
Set-ADUser $employee.SamAccountName -Replace $replaceHashTable
$count++
}

Write-Host $count " Accounts have been modified"

Populating Active Directory with Users and Groups with PowerShell

I whipped up this script in order to populate my Lab VM running Windows Server 2008 R2 with users and groups. Plus I was bored and wanted to work on my PowerShell 🙂

I did have to load an update so that I could run a few of the cmdlets(New-ADUser, New-ADGroup, & Add-ADGroupMember) you can find the update and info on it here http://support.microsoft.com/kb/2806748

#### Create Users and Groups in Fresh AD ####
#### I use this script to populate users and groups on a test server ####
#### Load Active Directory Module ####
Import-Module ActiveDirectory

#### CSV Format Below ####
## FirstName,LastName,UserName,Password,EmailAddress,Group1,Group2,Group3,Group4,Group5,Group6,Group7,Group8,Group9,Group10,Group11,Group12
## A. Scott,Wright,ascott0,WrA.57co,ascott0@adventure-works.com,DesktopAdmins,,Production Control,,,,,,,,,



### Import our CSV File ###


$UserList = Import-Csv "C:\ADShare\Powershell\AddUsers.csv"

$EmployeeOU = "OU=Employees,DC=lmnop,DC=local"


foreach ($User in $UserList){
	$FullName = $User.FirstName + " " + $User.LastName
	$Password = $User.Password
	$SAM = $User.UserName
	
	##Build Group List##
	$GroupList = @( 
	 $User.Group1
	,$User.Group2
	,$User.Group3
	,$User.Group4
	,$User.Group5
	,$User.Group6
	,$User.Group7
	,$User.Group8
	,$User.Group9
	,$User.Group10
	,$User.Group11
	,$User.Group12)
	
	
	##Create User##
	New-ADUser -Name "$FullName" -SamAccountName $SAM -UserPrincipalName $SAM -DisplayName "$FullName" -GivenName $User.FirstName -Surname $User.LastName -EmailAddress $User.EmailAddress -AccountPassword ( ConvertTo-SecureString $Password -AsPlainText -Force) -Enabled $true -Path "$EmployeeOU" -PasswordNeverExpires $true
	
	
	
	##Check if group exists and Create if needed##
	Foreach($ADGroup in $GroupList){
		#Skip blanks
		if($ADGroup -ne ""){
				if(Get-ADGroup -Filter{SamAccountName -eq $ADGroup}){
				#Write-Host $ADGroup ": Exists"
				#Add User to Group
				Add-ADGroupMember $ADGroup $SAM
				Write-Host "Added $SAM to $ADGroup"
				}else{
					#Write-Host $ADGroup ":Does Not Exist"
					#Create Group, Then add user to Group
					New-ADGroup -Name "$ADGroup" -Path "$EmployeeOU" -GroupScope Global
					Add-ADGroupMember $ADGroup $SAM
					Write-Host "Created Group $ADGroup"
					
				}
		}
	}
	

}

Here is the complete CSV file I used (basically from the AdventureWorks Sample DB) AddUsers.csv

PowerShell is always fun.

Learning PowerShell

Learning Powershell? You should take a look at PowerGUI!
This free gem will help you get at what you want.

Define a variable and run it(debug or F5) and keep an eye on your variables pane and you will instantly see the time savings 🙂 You will now be able to browse through all those option and find what you are looking for!
LearningPowerShell-PowerGUI

Give it a try 🙂

Easy Powershell Oneliner

As I post things on this blog about PowerShell I will attempt to note how to do it with and without aliases. Just remember when going through the interwebs you can always look up and alias by typing Get-Alias or just type Get-Alias to see the entire list.

PS C:\>Get-Alias ft

Here is a little nugget you can try:

Without aliases:

PS C:\>Get-WmiObject -Class win32_bios |Select-Object *

With aliases

PS C:\>gwmi -Class win32_bios |Select *

powershell-gwmi

PowerShell & PowerCLI

I have put off learning Windows PowerShell for too long. Which is really surprising, as I have done a lot of Perl and PHP in the past.

While I was a Student Linux Admin at Clark Community College (2001) I had written a Perl script for user account management on Computer Science Department RedHat box. The script took a CSV file with student ID’s and qualifying/disqualifying classes and created, disabled, and in some cases removed the account. If the account was going to be removed I would check the MySQL backend and if the user had an account that was disabled for 2 quarters then the account and user directory was removed at the start of the 3rd quarter.

I have done several Perl and PHP scripts, but one PHP script stands out.  We had put in a new ProxCard system to control our doors and gate and the software wasn’t usable for our non-technical staff.  I had to figure out where the ProxCard system was inserting records into the SQL database and once I figured that out I whipped up a couple of Perl scripts to test. Eventually this grew into a regular LAMP server with users accounts and auditing.

Yeah I really just wrote my second PowerShell/PowerCLI script a few days ago!

So my first script I wrote checked my vSphere cluster for VMs with multiple vCPUs (and no I didn’t do a “Hello World!”)

#Find all virtual destkops running on a cluster that have more than one vcpu

# Launch text
write-host "                                                                                  "
write-host "         Rob's First Script to check a cluster for VMs running more than one vcpu!" 
write-host "                                                                                  "


$cluster = Read-Host 'On Which cluster to you want to check for multiple vcpus?'

get-cluster $cluster | get-vm | select name,powerstate,numcpu,memorygb,host |where {$_.numcpu -gt 1 -and $_.powerstate -eq "PoweredOn"} |format-table -autosize


get-cluster $cluster | get-vm | select name,powerstate,numcpu,memorygb,host |where {$_.numcpu -gt 1 -and $_.powerstate -eq "PoweredOn"} |group-object -Property Host | Select Count, Name | format-table -autosize

I wrote my second script recently to find folders on a specific datastore. This datastore is used for a backup/archive snapshot for VDI using Unidesk. Currently when I remove a machine in Unidesk or restore to a different cachepoint we can end up getting orphaned files on the archive datastore.

#get-cluster cluster02
$cluster = "cluster02"

function CheckVM {
param([string]$vmname)
$VM = get-cluster $cluster | Get-VM -name $vmname -ErrorAction SilentlyContinue
   if(!$VM){ 
        $status = "No VM"
   }
   else { 
        $status = "VM Found" 
       }

return $status
}


#grab folders on archive tier datastore VDIBU

$cp1ap=  "vmstores:\vc01@443\DataCenter\VDIBU\Unidesk Backups\VDI01\User"
$cp2ap=  "vmstores:\vc01@443\DataCenter\VDIBU\Unidesk Backups\VDI02\User"

#exclude any . files if any and make sure it's a folder and not a file
$cp1Folders =
get-childitem -exclude .* $cp1ap | select name,PSIsContainer | where {$_.PSIsContainer -eq "True"} |foreach {$_.name}

#exclude any . files if any and make sure it's a folder and not a file
$cp2Folders =
get-childitem -exclude .* $cp2ap | select name,PSIsContainer | where {$_.PSIsContainer -eq "True"} |foreach {$_.name}


#combine arrays and print out hash to see if a MM has been restored to another CP at some point in time
$AFolders = $cp1Folders + $cp2Folders

$AFolders | group | % {$hash = @{} } { $hash[$_.Name] = $_.Count }

foreach ($key in $hash.GetEnumerator()){
    $vmExists = CheckVM $($key.Name)
    Write-Host "$($key.Name)    has $($key.Value) archive folders and: $vmExists" 
    }

I know it is ugly but it works 🙂