Purging the old login ScriptPath

In the advance in directory topologies over the years the use of batch or vbscript login scripts are slowly being phased out in favor of group policy based solutions which offer greater flexibility. Recently I had the need to purge the ScriptPath field from all users within an organization.

$myusers = Get-ADUser -Filter * -SearchBase "DC=liquidobject,DC=com" -properties ScriptPath | select-object SamAccountName,ScriptPath

Write-Host $myusers.count " users loaded."

foreach($user in $myusers)
{
    if($user.ScriptPath.length -gt 0)
    {
        Write-Host "Cleaning: " $user.SAMAccountName #" - " $user.ScriptPath
        Set-ADUser -identity $user.SAMAccountName -ScriptPath $NULL
        Sleep 0.1
    }
    else
    {
       # Write-Host "Already Clean: " $user.SAMAccountName
    }
    
}

AD user counts by first letter

When planning a deployment for a number of software packages for scaling one method of balancing the number of users across a series of groups is commonly done via alphabetical groupings based upon the username.

if(Get-Module -Name ActiveDirectory){}
else{Import-Module ActiveDirectory}

function CountUsers
{
	param([String]$mychar)
	$mycount = (Get-ADUser -Filter {SAMAccountName -like $mychar} -SearchBase "OU=My Users,DC=LiquidObject,DC=com" | Select-Object SAMAccountName).count
	Write-Host "" $mychar.SubString(0,1) " has: " $mycount " users."
}


CountUsers("A*")
CountUsers("B*")
CountUsers("C*")
CountUsers("D*")
CountUsers("E*")
CountUsers("F*")
CountUsers("G*")
CountUsers("H*")
CountUsers("I*")
CountUsers("J*")
CountUsers("K*")
CountUsers("L*")
CountUsers("M*")
CountUsers("N*")
CountUsers("O*")
CountUsers("P*")
CountUsers("Q*")
CountUsers("R*")
CountUsers("S*")
CountUsers("T*")
CountUsers("U*")
CountUsers("V*")
CountUsers("W*")
CountUsers("X*")
CountUsers("Y*")
CountUsers("Z*")
CountUsers("0*")
CountUsers("1*")
CountUsers("2*")
CountUsers("3*")
CountUsers("4*")
CountUsers("5*")
CountUsers("6*")
CountUsers("7*")
CountUsers("8*")
CountUsers("9*")

Bulk password resetting

In an effort to simplify bulk password resets. With a provided CSV of usernames with a “User” heading the below should easily reset their passwords in bulk and force them to pick a new password the next time they log onto a computer.

Import-Module ActiveDirectory
$User = Import-CSV "MyUsers.csv"
#Reset their password to a known common password
$User | Foreach {Get-ADUser -Identity $_.User | Set-ADAccountPassword -Reset -NewPassword (ConvertTo-SecureString -AsPlainText "Some_Random_Password_12345" –Force)}
#Force changing of the password at next login
$User | Foreach {Get-ADUser -Identity $_.User | Set-ADUser -Enable $True -ChangePasswordAtLogon $True}

WSUS repair after backup restoration

Last week during the process of updating a few services one of the WSUS servers had gone belly up. Installing over the top or performing an uninstall then a re-install did not clear up the issue. The next step was to perform a restore on the system (dedicated WSUS/Forefront for Exchange VM) from the last backup taken before the system started going south. The restore worked bringing back a WSUS instance which would talk to the clients without any issues but then I started seeing errors in the application event log. The errors were showing that recently approved updates which were in the database could not be found on the filesystem.

What I ran into was a catch-22 when performing an enterprise deployment of WSUS where the SQL instance is on another VM separate from the WSUS server. Restoring the SQL database is possible but it may or may not be exactly when the backup of the WSUS instance was so I opted the other option which allows for the existing database to remain intact.

1) Stop the “Update Services” and two IIS services
2) Delete everything found in the WsusContent folder, while it can be skipped I wanted to make sure everything was cleanly downloaded
3) Open up a command line
4) cd “\Program Files\Update Services\Tools
5) wsusutil.exe reset

This will issue a full verification of the WSUS installation and pull down all of the approved updates. Which at this point the 30GB or so of updates took a few hours to rebuild the entire local cache. At which time, updates began to flow normally.

Hiding Distribution Group memberships

Under Exchange 2010 the need arose to create some distribution groups which the membership was hidden. The most published method is to actually use two groups. The first is a non-mail enabled group and the second is a dynamic distribution group. While these do have there place in many organizations I wanted to maintain the same functionality without needing the second group.

To keep my life simple here is the PowerShell method to this problem.

Lets define some variables

$listname = "allemployees"
$orgunit = "liquidobject.com/Exchange/Distribution Groups"
$managedby = "MyDummyAdmin"
#Build the Group
New-DistributionGroup -Name $listname -SamAccountName $listname -OrganizationalUnit $orgunit -Type "Distribution" -ManagedBy $managedby -MaxReceiveSize "5120 KB"
sleep 4
#Restrict commandline to view membership via net group command
Add-ADPermission -Identity $listname -User "Normal_Employee_Group" -Deny -AccessRights ReadProperty -Properties Member
#Restrict Outlook & OWA Access to view membership
set-ADGroup -identity $listname -Replace @{HideDLMembership=$true}

This method has been used in the past via ADSI Edit but I was looking for a native PowerShell approach for a process to automate group creation.

The only drawback is the HideDLMembership is organization wide, so regular managers cannot see the group memberships. Administrators can still see membership via the EMS, EMC, or via the old net group method.

Messagetracking log compilation

If you ever needed to quickly all external messages sent to your organization but have the problem of multiple transport servers, the below script should help give some insight into the messages recently received.

$myminutes = 1
$myservers = "cashub-1","cashub-2","cashub-3"
$mydomain = "testdomain.local"

cls
$mystart = (Get-Date).addminutes(-$myminutes)
foreach($myserver in $myservers)
	{
		Write-host "------------------- start " $myserver "-------------------"
		Get-MessageTrackingLog -Start $mystart -server $myserver | where {($_.Sender -notlike "*$mydomain") -and ($_.Source -eq "SMTP")}
		Write-host "-------------------   end " $myserver "-------------------`n"
	}