VBScript to disable all users in specified OUs

When staff members leave the organisation, we move their account to a sub-OU named “Leavers” under their office’s OU. This triggers their mailbox to be archived in Enterprise Vault.

I thought it was about time to put together a quick scheduled task to ensure that all these “leavers” were automatically disabled and hidden from the Exchange address lists without IT manually having to do it.

I came across this handy and concise example, and modified it to run through a group of OUs while doing what I needed it to do.

Here’s the code. As always, run at your own risk, and test it before putting it into production:

On Error Resume Next

Dim arrLeaverOrgUnits, objOU
arrLeaverOrgUnits = Array("LDAP://OU=Leavers,OU=Sydney,DC=contoso,DC=com",_
                          "LDAP://OU=Leavers,OU=Melbourne,DC=contoso,DC=com")

For Each strOU in arrLeaverOrgUnits
  Set objOU = GetObject(strOU)
    ' Let's be extra-paranoid here, and make sure we're only working on the leavers OU
    '  in case someone adds the wrong OU into the array above
    If objOU.Name <> "OU=Leavers" Then Exit For
    
    ' Loop through each object in the current OU
    For Each objObject In objOU
      ' If the current object is a user
      If objObject.class="user" then
        'Disable the account
        objObject.AccountDisabled = True
        ' Hide the account from the Exchange address lists
        objObject.Put "msExchHideFromAddressLists", True
        ' Write the information back to the user object in AD
        objObject.SetInfo
        
        'WScript.Echo objObject.Name & " disabled and hidden from Exchange address lists"
      End if
    Next
  Set objOU = Nothing
Next

PowerShell: Cancel all print jobs

Here’s a quick PowerShell script I put together to delete all print jobs from our Windows Server 2008 R2 print server. It’s run overnight as a scheduled task. We do this because sometimes our print accounting software doesn’t clear out old jobs if users haven’t released them at the printer.

EDIT: January 2015

Just reviewing my old posts. Here’s how I’d do this nowadays:

Get-WmiObject Win32_Printer -Filter "(Local = $true) and (Shared = $true)" | ForEach-Object {$_.CancelAllJobs()}

It’s better practice to do the filtering in WMI earlier, rather than retrieve more printers and filter them out in PowerShell afterwards.

Here’s the old code

$printers = Get-WmiObject Win32_Printer

if ($printers.Count -eq 0) {
    Write-Host -ForegroundColor red "No Printers Found"
    exit
}

foreach ($printer in $printers) {
    
    if ($printer.Local -and $printer.Shared)
    {
        Write-Host -ForegroundColor Green "Cancelling all jobs on: $($printer.Name)"
        $printer.CancelAllJobs()
        
    }
}

It will only clear print jobs on local printers that are shared out. There’s some more info about the Win32_Printer class and the CancelAllJobs method on MSDN.

Note that I haven’t included any error-checking in this script at all, so run it manually first to see if it will work. As always, run at your own risk.

To schedule it, simply create a new scheduled task:

    1. Run with highest privileges
    2. Run whether user is logged on or not
    3. Do not store password
    4. Action: Start a program: C:WindowsSystem32WindowsPowerShellv1.0powershell.exe
    5. Arguments: -File “C:path-to-script-filename-of-script-file.ps1”

clearqueues-generaltab

clearqueues-action

Updated: VBScript – Check if current user is a member of a certain group

I found some code to do this out on the net the other day. I’ve modified it a little, and added the part that checks environment variables.

Note 3: 30th May 2014 – This post is consistently one of the most popular posts on my blog. By now, you should be looking at PowerShell to replace VBScript. The 40-odd lines of VBScript below can be replaced by a single line of PowerShell. See this post here.

Note 2: 21st February 2013 – I’ve updated the script so that it will work with Option Explicit. People who used this would see every check returning “true”. Thanks to “Zounder1” for making me aware of this.

Note: 11th October 2010 – Since this post is so popular, I’ve cleaned up the code a bit and re-posted it below.

Option Explicit
Dim objShell,grouplistD,ADSPath,userPath,listGroup
On Error Resume Next

set objShell = WScript.CreateObject( "WScript.Shell" )
 
'Calls the isMember function with the specified group to see if the current user
' is a member of that group.
If isMember("GroupNameToCheckGoesHere") Then
       'MsgBox("Is member") ' Do something here if they are a member of the group
    Else
       'MsgBox("Is not member") ' Do something here if they are not a member of the group
End If
 
' *****************************************************
'This function checks to see if the passed group name contains the current
' user as a member. Returns True or False
Function IsMember(groupName)
    If IsEmpty(groupListD) then
        Set groupListD = CreateObject("Scripting.Dictionary")
        groupListD.CompareMode = 1
        ADSPath = EnvString("userdomain") & "/" & EnvString("username")
        Set userPath = GetObject("WinNT://" & ADSPath & ",user")
        For Each listGroup in userPath.Groups
            groupListD.Add listGroup.Name, "-"
        Next
    End if
    IsMember = CBool(groupListD.Exists(groupName))
End Function
' *****************************************************
 
' *****************************************************
'This function returns a particular environment variable's value.
' for example, if you use EnvString("username"), it would return
' the value of %username%.
Function EnvString(variable)
    variable = "%" & variable & "%"
    EnvString = objShell.ExpandEnvironmentStrings(variable)
End Function
' *****************************************************
 
' Clean up
Set objShell = Nothing

Self-sign your Powershell scripts

Creating my first Powershell script, I came up against code execution issues. Rather than take the easy (sketchy) way out and simply enable execution of unsigned code, I went and figured out how to sign my scripts using my internal CA. Powershell’s internal help is very useful also:

get-help about_signing

My CA is (still) a Windows Server 2003 DC, so that’s what this is based on.

  1. Connect to your CA using the Certification Authority snapin, and ensure that the Code Signing certificate template is enabled/loaded. If it isn’t, just right-click on Certificate Templates and select New –> Certificate Template to Issue

    image
  2. Ensure that HTTPS is enabled for your CA’s Certificate Services virtual directory, and then navigate to it using IE from your own PC;

    https://{CA-name}/certsrv
  3. Go to Request a certificate, User Certificate (click Yes, to any IE popups at this point), go to More Options >>>, Use the Advanced Certificate Request form, select the Code Signing certificate template, and then Submit your request.
  4. Once your certificate is issued and installed, you’ll be able to view its details using this Powershell command:
  5. Get-ChildItem cert:CurrentUserMy -codesigning
  6. Sign your Powershell script with the following command. I ran into an issue where I received an “Unknown Error”, but this turned out to be because I had created the script from within the Powershell ISE. This handy blog post helped me out.
  7. Set-AuthenticodeSignature .{script name}.ps1 @(Get-ChildItem cert:CurrentUserMy -codesigning)[0]

There’s some pretty useful info here, on powershell.com

Windows XP Print-Mapping Automation

Found a useful feature in Windows XP the other week when stuffing around with print-mapping scripts. Instead of using the old con2prt feature to connect to printers, you can use Windows’ inbuilt printing APIs to map printers, add new drivers from INF files, remove printer mappings, remove drivers, and much more.

The main reason I like this over the old con2prt.exe is that you can remove individual mappings to printers – you don’t have to remove all the mapped printers at once with a ‘con2prt /f’ if you don’t want to.
Continue reading

Microsoft Identity Integration Feature Pack (IIFP)

When looking for a solution on how to synchronise our Exchange GALs between two seperate forests, I came across this Microsoft feature pack – which is freely available to download from their website.

What IIFP does according to Microsoft: “Identity Integration Feature Pack 1a for Microsoft® Windows Serverâ„¢ Active Directory® manages identities and coordinates user details across Microsoft Active Directory, Active Directory Application Mode (ADAM), Microsoft Exchange 2000 Server, and Exchange Server 2003 implementations. ”

The download link:
IIFP Download

There’s only one catch: you need an enterprise version of Windows 2003 Server to be able to install the feature pack. A little birdie tells me that if you use Orca from the Windows 2003 Server SDK, you can modify the installation requirements to get it working on a non-enterprise version of Windows 2003 Server.

IIFP on Windows 2003 Server Std.

Here’s a tutorial from MSExchange.org on GAL synchronisation:
http://www.msexchange.org/pages/article_p.asp?id=668

I couldn’t end up getting it to work because of domain naming issues between the two domains (one is named as a parent of the other one without actually being the AD parent domain), but it looks like it could be a very useful tool.