Archive | December, 2011

Updated PowerShell to determine if a user is visiting the office

I made an error. More like an incorrect assumption in this post, specifically this code.:

Function JBMURPHY-AD-GetHomeSite {
Param($username=$(cat env:username))
foreach ($group in "OfficeGroup1","OfficeGroup2","OfficeGroup3") {
    foreach ($user in $(Get-ADGroupMember $group)){
    if ($user.SamAccountName -eq $username) {return $group}
    }
}
}

My incorrect assumption was that the AD PowerShell components were installed on every machine (they are only my machine). I needed to rewire this code above to use ADSI, since Get-ADGroupMember is not on everyone’s machine. Below is that code:

Function JBMURPHY-AD-GetHomeSite {
Param($username=$($env:USERNAME))
$groups=([AdsiSearcher]"samaccountname=$username").Findone().properties.memberof | % {([adsi]"LDAP://$_").cn}
foreach ($officegroup in "OfficeGroup2","OfficeGroup2","OfficeGroup3") {
    foreach ($group in $groups){
    if ($group -eq $officegroup) {return $group}
    }
}
}

PowerShell wrapper function to display a dialog box

I wanted a function that I could pass some text, and it would put that text in a dialog box for the user to click okay. Simple, but I will reuse it I am sure.

 

Function JBMURPHY-DisplayWindowsForm(){
Param([parameter(Mandatory = $true)]$TextToDisplay,
$Title="DefaultTitle")
		[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 
		[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
		$objForm = New-Object System.Windows.Forms.Form 
		$objForm.Text = $Title
		$objForm.Size = New-Object System.Drawing.Size(600,500) 
		$objForm.StartPosition = "CenterScreen"
		$OKButton = New-Object System.Windows.Forms.Button
		$OKButton.Location = New-Object System.Drawing.Size(250,400)
		$OKButton.Size = New-Object System.Drawing.Size(75,23)
		$OKButton.Text = "OK"
		$OKButton.Add_Click({$x=$objTextBox.Text;$objForm.Close()})
		$objForm.Controls.Add($OKButton)
		$objLabel = New-Object System.Windows.Forms.Label
		$objLabel.Location = New-Object System.Drawing.Size(10,20) 
		$objLabel.Size = New-Object System.Drawing.Size(500,400) 
		$objLabel.Text = $TextToDisplay
		$objForm.Controls.Add($objLabel) 
		$objForm.Topmost = $True
		$objForm.Add_Shown({$objForm.Activate()})
		[void] $objForm.ShowDialog()
}

After removing last Exchange 2003 Server, mail enabled public folders no longer work

We decommissioned our last Exchange 2003 server the other day. All seamed well and I thought we were done.

Nope.

A few days later we had our scheduled downtime to apply patches, and I rebooted all three of our Exchange 2010 servers (for the record we are Exchange 2010 SP1 UR3 v3). Next morning people were getting bounce backs from messages destined to mail enabled public folders. The error  in the bounce back was:

#554 5.2.0 STOREDRV.Deliver.Exception:ObjectNotFoundException; Failed to process message due to a permanent exception with message The Active Directory user wasn’t found. ObjectNotFoundException: The Active Directory user wasn’t found. ##

I found this thread and this post. The error (as both posts suggested) boiled down to an empty server container from the decommissioned Exchange 2003 infrastructure. This blog post recommend against cleaning all the old entries, so we were nervous about making the change. Seemed unlikely that a single EMPTY container would be causing such a large issue.

We contacted technical support (without mentioning our findings) and they said the exact same thing as our findings above – to remove the empty servers container. When I asked why this single container is causing the problem, they said “This happens because we assume that if a Servers container exists, there will be a System Attendant object somewhere inside it.” To me, this really does not explain “why”, but it was all they offered. We also asked if the deletion of the servers container would impact any other systems and they said “no”. Our final question was: once deleted, did we need to restart services/servers, and they said “no”.

We backed up AD (system state and the C: drive of the PDC) and deleted the empty servers container, held our breath, and . . . all was good. Mail immediately started flowing to the mail enabled public folders.

I thought I would write this up to supplement the above posts, and to add to our experience. Maybe this will help some one? Leave a comment if this helped!

PowerShell script to change default prf imported when Outlook starts up for the first time

In this previous post, I talk about how we use Office Customization Tool (OCT) and “.prf” files to deploy Office 2010. Continuing with the idea that  I want to know if a person is visiting from another office, I want to be able to switch from our default of “cached mode” to “online mode” for that visitor. I wrote this script with the logic of: IF {visiting from other office}, THEN {JBMURPHY-Install-ChangeDefaultOutlookPRF -CachedMode $false}.

This script would change where the ImportPRF registry entry points (in this example to a “.prf” file with cached mode disabled)

function JBMURPHY-Install-ChangeDefaultOutlookPRF {
 PARAM($CachedMode=$TRUE)
foreach ($PATH in (gci "HKLM:\SOFTWARE\Microsoft\Office\14.0\User Settings\*{*")){
 $ImportPRFRegPATH=$PATH.Name.Replace("HKEY_LOCAL_MACHINE","HKLM:")+"\Create\Software\Microsoft\Office\14.0\Outlook\Setup"
 If (Test-Path $ImportPRFRegPATH){
  $ImportPRFPath=$(get-itemproperty($ImportPRFRegPATH)).ImportPRF
  write-host -NoNewline "`nIportPRF=$ImportPRFPath - "
  if ($CachedMode) {
	if ($ImportPRFPath -eq "C:\PROGRA~1\MICROS~1\WITHCA~1.PRF") { write-host "Already in CachedMode"}
	else {write-host "Enabling CachedMode"
	Set-ItemProperty $ImportPRFRegPATH -Name ImportPRF -Value "C:\PROGRA~1\MICROS~1\WITHCA~1.PRF"
	write-host "Now IportPRF=$($(get-itemproperty($ImportPRFRegPATH)).ImportPRF)"
	}
  }
  else {
	if ($ImportPRFPath -eq "C:\PROGRA~1\MICROS~1\WITHOU~1.PRF") { write-host "CachedMode already turned off"}
	else {write-host "Turning Off CachedMode"
	Set-ItemProperty $ImportPRFRegPATH -Name ImportPRF -Value "C:\PROGRA~1\MICROS~1\WITHOU~1.PRF"
	write-host "Now IportPRF=$($(get-itemproperty($ImportPRFRegPATH)).ImportPRF)"
	}
  }
 }
}

A script to loop through a WordPress database and search for text

We maintain both a WordPress development environment and a production environment. I have written a script that copies a WordPress site to the local machine. In that script I change the GUID (even thought this page says you shouldn’t), siteurl, and home. I change the GUID, because the site has not been publicly accessible, so I believe the warning on the documentation page does not apply.

One thing that I always wanted to do is make sure that the old (dev) site url is not elsewhere in the database. So I figured out this script below that loops thorough all the tables, and all the columns in the database searching for text, in this case the old site url.

DATABASENAME="mywpdb"
SEARCHTEXT="devURL"

for TABLE in $(mysql --batch --skip-column-names -e "use $DATABASENAME;show tables"); do
for COLUMN in $(mysql --batch --skip-column-names -e "use $DATABASENAME;SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = '"$TABLE"' AND TABLE_SCHEMA = '"$DATABASENAME"';"); do
query="use $DATABASENAME;select substring($COLUMN,1,100) as '"$TABLE":"$COLUMN"' from $TABLE WHERE $COLUMN like '%"$SEARCHTEXT"%';"
mysql -e "$query"
done
done

PowerShell: Two functions to determine if a user is visiting the office

If you have users in distribution groups associated with each site in your organization, it should be easy to tell if a user is visiting from another office (more on why I want to do this later). First function returns the current site that the user is logging into:

Function JBMURPHY-AD-GetCurrentSite {
return [System.DirectoryServices.ActiveDirectory.ActiveDirectorySite]::GetComputerSite().name
}

The second function loops through all “office groups” and if a user is in that office, it returns the group name


Function JBMURPHY-AD-GetHomeSite {
Param($username=$(cat env:username))
foreach ($group in "OfficeGroup1","OfficeGroup2","OfficeGroup3") {
	foreach ($user in $(Get-ADGroupMember $group)){
	if ($user.SamAccountName -eq $username) {return $group}
	}
}
}

Simple I know, but I want to put these together to do some custom startup activity (maybe via “Active Startup”)

PowerShell to verify ACLs (permissions) on a folder

In my previous post, I showed how to create a new ACL and apply it to a folder. Why apply it to the folder if the folder is already set correctly? I wrote the following function to compare the ACLs of a folder to a desired set of ACLs (either created by hand (lines 3-12) or copied from an existing folder (lines 12-15).

function JBMURPHY-PERMS-ArePermsCorrect {
        Param([parameter(Mandatory = $true)]$Path,
              [parameter(Mandatory = $true)]$CorrectACL,
              [switch]$ShowCorrect)

    $folderACLs=get-acl(get-item $Path)
    if ((compare-object $($folderACLs.access) $($CorrectACL.access) -property FileSystemRights,IdentityReference,InheritanceFlags,PropagationFlags).count -gt 0) {
    Write-host "$PATH is INCORRECT"
    return $false
    }
    else {
    if ($ShowCorrect.IsPresent){write-host "$PATH is correct"}
    return $true
    }
}

If the compare-object command returns nothing, then they are the same, if they are not the same then the items returned will be greater than 0, and the first part of the conditional will be used.

PowerShell to assign permission to a folder (not copy inherited permissions)

In my previous post, I used PowerShell to change the permissions of a top level folder. In that script, I took the folder in question and copied the inherited permissions to it, and then I tinkered it to be what I wanted. I wanted to do something similar, but I wanted a set of permission that differed from the parent. Basically I wanted the folder to have unique permissions. Below is the function to do that:

function JBMURPHY-PERMS-ClientsFolderReBase {
    Param([parameter(Mandatory = $true)]$Path)
    $correctACLs = New-Object System.Security.AccessControl.DirectorySecurity
    $correctACLs.SetAccessRuleProtection($true,$true)
    $Rule_Admin = New-Object Security.AccessControl.FileSystemAccessRule("BUILTIN\Administrators",@("FullControl"),"ContainerInherit, ObjectInherit","None","Allow")
    $Rule_System = New-Object Security.AccessControl.FileSystemAccessRule("NT AUTHORITY\SYSTEM",@("FullControl"),"ContainerInherit, ObjectInherit","None","Allow")
    $Rule_Users1 = New-Object Security.AccessControl.FileSystemAccessRule("BUILTIN\Users",@("ReadAndExecute", "Synchronize"),"None","None","Allow")
    $Rule_Users2 = New-Object Security.AccessControl.FileSystemAccessRule("BUILTIN\Users",@("Modify, Synchronize"),"ContainerInherit, ObjectInherit","InheritOnly","Allow")
    $correctACLs.AddAccessRule($Rule_Admin)
    $correctACLs.AddAccessRule($Rule_System)
    $correctACLs.AddAccessRule($Rule_Users1)
    $correctACLs.AddAccessRule($Rule_Users2)
    write-host "Changing $Path"
    set-acl $path $correctACLs
}

In line 3 I create a new ACl, and in line 4, I set the cal to not inherit parent permissions.

Lines 4-8 are the specific permissions I want to apply (they are addressing the same issue I described here)

Lines 9-12 add the new perms to the new ACL, and line 14 set the ACL of the folder to the new ACL.

A little different want o go about this, as I created an ACL from the start.