Posted by & filed under Blog.

Hey, here’s a quick liner to remove all members of a Distribution Group in Exchange (2007 in my test case). This came in useful for me when trying to routinely repopulate a distribution group via scheduled task. It’s not particularly fast I must apologize. Please comment if you know of any faster methods to clear a group’s membership.

Get-DistributionGroupMember -Identity 'my.group@domain.local' | Remove-DistributionGroupMember -Identity $identity -Confirm:$False;

This should only work when excuting directly from and Exchange server. If you are using a PS remote session to connect to an exchange server, you may run into the following error:

Pipeline not executed because a pipeline is already executing. Pipelines cannot be executed concurrently.

I resolved this by first caching the results of ‘Get-DistributionGroupMember’ to a variable and then piping it through to ‘Remove-DistributionGroupMember’ (thanks to advice from Mike Pfeiffer).

$identity = 'my.group@domain.local';
$members = Get-DistributionGroupMember -Identity $identity
$members | foreach { Remove-DistributionGroupMember -Identity $target -Member $_.DistinguishedName -Confirm:$False };

You may ask why I don’t just use a Dynamic DG instead of scheduling a script? In my case, the DG needs to be populated with linked mailboxes from the Exchange domain according to security group memberships in seven external domains.

Posted by & filed under Blog.

So I ran into this spot of bother today trying to establish a remote session from one server to another server in PowerShell:

[servername] Connecting to remote server failed with the following error message : The server certificate on the destination computer (servername:443) has the following errors:
The SSL certificate could not be checked for revocation. The server used to check for revocation might be unreachable.
For more information, see the about_Remote_Troubleshooting Help topic.
+ CategoryInfo : OpenError: (System.Manageme….RemoteRunspace:RemoteRunspace) [], PSRemotingTransportExc
eption
+ FullyQualifiedErrorId : PSSessionOpenFailed

I’m fairly certain its a firewall issue with the server unable to access the CA for verification, but in this case I don’t care; I just want to establish the session.

If you are experiencing the same issue, one solution is to create and pass a new PSSessionOption object that specifies that all certificate checks should be bypassed.

Here’s how:

$sessionOption = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
$session = New-PSSession -ConnectionUri $yourUrl -Credential $credential -Authentication Basic -AllowRedirection -SessionOption $sessionOption
Import-PSSession $session

Hope it helps!

Posted by & filed under Blog.

I’ve just uploaded a significant release for WMI Studio. This version addresses a number of bugs as well as introducing the some new features.

The project is still a fair way from producing a ‘stable’ release as I work out all the variables and pitfalls in working with WMI but the release is highly usable and a fantastic productivity tool. Of course your feedback is highly appreciated and will facilitate more frequent releases.

This release introduces the following new features:

  • Intelligent query builder
  • Support for ‘ASSOCIATORS OF’ and ‘REFERENCES OF’ queries
  • Object inspector for expanding WQL results
  • Improved XML and CSV exporting of results
  • Improved scripting engine
  • Improved remote connections

Head on over to the project page, WMI Studio to download the latest version.

Posted by & filed under Blog.

Often VBScripts will be required to determine if a given user (or object) is a member of a given AD / LDAP group. For example this is useful for determining which network drives a user should mount during logon, based on their group memberships. A common issue with most script samples is that they will not account for nested group memberships.

As an example, you may have an AD group named ‘Res-Share-Public’ which is designated to grant access to your public share. The group may only contain other groups, such as departments or business groups which in turn contain the end users.

The following VBScript function will return true when testing a grandchild user account against the grandparent group, ‘Res-Share-Public’:

Function IsMember(strUserDN, strGroupDN)
	Set objGroup = GetObject(strGroupDN)
	For Each objMember in objGroup.Members
		If (LCase(objMember.Class) = "group") Then
			If (IsMember(strUserDN, objMember.AdsPath)) Then
				IsMember = True
				Exit Function
			End If
		Else
			If (objMember.distinguishedName = strUserDN) Then
				IsMember = true
				Exit Function
			End If
		End If
	Next
	Set objGroup = Nothing
	IsMember = False
End Function

The strUserDN and strGroupDN parameters must be the full Distinguished Name of the objects prefixed with “LDAP://” (ie. ADS Path format) to work correctly.

The function will return true if the User is a direct or nested child (grandchild, great-grandchild, etc) of the specified Group.

This sample is free for you to use with attribution greatly appreciated. As always, your feedback is welcomed.

Posted by & filed under Blog.

I’ve found some fantastic HTML5 <canvas> experiments at Hakim El Hattab’s site, here: http://hakim.se/experiments (Not to mention a beautifully design site).

Now having seen how well complex animations perform in modern browsers, I’m feeling much more inspired to starting animating stuff. Time to brush up on my maths.

You can see my sophisticated sketch here: http://hakim.se/experiments/html5/sketch/#41846db9

 

Posted by & filed under Blog.

I recently installed IIS7 on a Windows 7 workstation via batch file. The installation went off without a hitch but I was getting no response from http://localhost and a quick inspection of the IIS Manager snap-in showed that all my websites and application pools were stopped. I tried to start the Default App Pool but this is what I got:

Application pool cannot be started unless the Windows Process Activation Service (WAS) is running.

The Service snap-in showed that WAS was not running. When I tried to start it I got:

Error 2: The system cannot find the file specified.

Thanks to Scott Hanselman’s efforts, I found the answer in his article Fixed: “Windows Process Activation Service (WAS) is stopping because it encountered an error.”.

All that was required was to create the folder ‘C:\inetpub\temp\apppools‘. That’s it!

Once created, start the Windows Process Activation Service and World Wide Web publishing Service and you should be away! Also, make sure they are set with Startup Type, Automatic

Posted by & filed under Blog.

Most organizations will want to bypass their proxy server for local web servers (intranet, CMS, helpdesk, etc). You can manually add each new server to your exception list in your logon script or group policies or simply use this PAC script to determine if a server is local and bypass it automatically!

You can use built in commands such as isInNet() which use potentially slow DNS lookups, but this method uses Regex queries instead.

/*
 *  Web Proxy Auto-Discovery Protocol Script
 *  Written by Ryan Armstrong
 *  http://www.cavaliercoder.com
 */
function FindProxyForURL(url, host)
{
	// Proxy server in format "PROXY [proxy server]:[proxy port]"
	var proxy = "PROXY proxy.mydomain.local:8080";
	
	// Proxy Exceptions:
	var exceptions = new Array(
	
		// Non-domain hostnames (eg. intranet, helpdesk, timesheets, etc)
		/^[a-zA-Z0-9-]+$/,
		
		// Local domain hosts (eg. fileserver.mydomain.local)
		/\.mydomain\.local$/,
		
		// Local IP Addresses (ie. 192.168.0.1 - 192.168.255.254)
		/^192\.168\.\d+\.\d+$/,
		
		// Local IP Addresses (ie. 172.16.0.1 - 172.32.255.254)
		/^172\.(1[6-9])|(2[0-9])|(3[0-2])\.\d+\.\d+$/,
		
		// Local IP Addresses (ie. 10.0.0.1 - 10.255.255.254)
		/^10\.\d+\.\d+\.\d+$/,
		
		// A domain and all of its subdomains:
		/microsoft\.com$/,
		
		// A domain and NONE of its subdomains:
		/^news\.google\.com$/
	);
	
	for (i = 0; i < exceptions.length; i++) // Iterate through each exception
	{
		if (exceptions[i].test(host)) // Test regex query against hostname
		{
			return "DIRECT"; // Bypass the proxy
		}
	}
	
	return proxy; // Connect via proxy
}

With each URL request, a client's browser will execute the FindProxyForURL() function and pass it the URL string and domain host name for the request. The function needs to return a string telling the browser to connect directly, via SOCKS or via a Proxy.

Be sure to update the exception and proxy address appropriate to your needs.

The script can be found and configured automatically by most browsers if it is made available via HTTP and advertised via DHCP or DNS. Firefox and Chrome (to my knowledge) don't support the DHCP method, but most browsers support DNS.

To have your script found via DNS is must be made available at 'http://wpad.mydomain.local/wpad.dat' where 'mydomain.local', need I say it, is your local domain. To do this, I saved the script as 'wpad.dat' in the root directory of my intranet server and created a DNS CNAME record (alias) pointing to that server named 'wpad'. You must also set the MIME type of the file to 'application/x-ns-proxy-autoconfig' or the file won't download (at least from IIS in my case). See Configure MIME Type (IIS 6.0) on Technet.

If you do also want to advertise the script via DHCP (it can't hurt), simply add Option 252 to your scope options containing the URL of your script. According to this article, IE6 may require the URL to be NUL terminated.

Here's another handy tip: if you want to test the functionality of the script, you can use the following PHP script (if PHP is configured on your web server) to immediately test the result of any specified host name. Save the following script as 'index.php' in the same folder as your proxy script and browse to 'http://wpad.mydomain.local'.

<html>
	<head>
		<script language="javascript">
<?php require_once('wpad.dat'); ?>

function testHost(host)
{
	document.getElementById('result').innerHTML = FindProxyForURL('', host);
}
		</script>
	</head>
	<body>
		<h1>Proxy Config</h1>
		<p>Enter the desired hostname to discover which proxy will be used.</p>
		<input type="text" onKeyUp="testHost(this.value)" size=30/>
		<span id="result" />
	</body>
</html>

Further Reading:

Wiki page with an overview: http://en.wikipedia.org/wiki/Web_Proxy_Autodiscovery_Protocol

Microsoft examples for IE: http://technet.microsoft.com/en-us/library/dd361950.aspx

IE Proxy Result Caching: http://support.microsoft.com/kb/271361

Publishing via Apache: http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/web-browser-auto-proxy-configuration.html

Best Practices: http://www.websense.com/content/support/library/web/v76/pac_file_best_practices/PAC_best_pract.aspx

Posted by & filed under Blog.

Since installing OS X Lion on a MacBook Pro at work, I’ve had a problem starting Outlook 2011. Outlook displays the splash screen for less than a second and then exits without a trace.

I did find the following error in the system logs by typing ‘tail /var/log/system.log‘ in a Terminal window.

com.apple.launchd.peruser.501[552] ([oxo-ox7a07a]).com.microsoft.Outlook[1448]) Exited with exit code: 255

I’m not sure what causes the problem but Microsoft did tell us to anticipate some issues with Outlook 2011 on OS X Lion in this article here. Fortunately this issue is easy to fix and does not seem to reoccur, but does require you to reconfigure your email accounts.

To fix the problem, you need to reset your Office Identities. There is no need to touch the plist files or create new user accounts. Simply rename ‘~/Documents/Microsoft User Data/Office 2011 Identities‘ to ‘Office 2011 Identities.backup‘ (Press ‘Return‘ to rename once selected in Finder). Please note that tilde (~) is a shortcut to your home folder in OS X and other *nix based operating systems.

Outlook should now open but will require you to recreate your mail accounts. I did so with an Exchange account so all mail items and contacts, etc were still available. I’m not sure if this would be the case with POP3 / IMAP accounts but take heart because you have a backup of your old Identities folder to pull files from! See the article Your Office Identity for more information on the Identities folder.

Please let me know if this solution works for you.

Posted by & filed under Blog.

After upgrading to OS X Lion 10.7 on both my iMac and Mac Book Pro, I’m interrupted by an ambiguous ‘Connection Failed‘ error every time I attempt to list AFP shares on one system from the other in Finder. There are various hints around the web suggesting that this is a bug and that it can be solved by creating another user account, repairing disk permissions or even just switching from AFP to SMB (Windows sharing). Good news is, if your issue is identical to mine, the solution is much simpler and less obtrusive.

In my case, I had the home folder for my user accounts shared on both Macs. Simply remove the home folder file share and all is well. To do this, open the Apple menu, open System Preferences -> Sharing -> File Sharing and then select your home folder (named after your user account) and click the ‘-‘.

To gain access to the home folder from each Mac, simply click ‘Connect As‘ in Finder and enter the appropriate credentials for the user who owns the home folder on the Mac you are connecting to. The home folder (and hard disk root) is automatically available!

Although it is frustrating that this is not either reported to the end user as an issue or automatically resolved, I’d suggest that the concept is more in line with security best practice for network file sharing. Any files to be shared really should be in a public folder, not your personal home folder (says me who had my home folder shared).

For what it’s worth, I’m enjoying the $30 upgrade. Full screen apps are nice (NI Traktor finally works full screen when switching desktops), Airdrop is fool proof and the reverse scrolling is actually oddly natural.

Posted by & filed under Blog.

A major frustration in SugarCRM (v 1.6.1) is that the style and formatting of outgoing emails do not match what is presented to the user in the email composer window. This is because the CSS styling which is applied to content in the composer window is not attached to the outgoing email. The solution is simple; attach the CSS content of the composer window (TinyMCE) to all outgoing emails. Here’s how:

First, set the default styling in: ‘/include/javascript/tiny_mce/themes/advanced/skins/default/content.css‘. Be sure to add the ‘div.email‘ selector so that the styling is also applied to the main container of the outgoing emails.

body, td, p, pre, div.email {
	color:#000; 
	font-family: Arial, Verdana, Helvetica, sans-serif;
	font-size:12pt; 
	margin:8px;
}

Apply some tweaks to the way TinyMCE renders HTML for your emails in: ‘/modules/Emails/javascript/init.js‘ (Line ~55) by adding the following to the tinyMCE.init() parameters:

// Force new lines to be <p> elements.
force_br_newlines : false,
force_p_newlines : true,
// Set available font sizes to static sizes, as opposed to relative sizes such as 'xx-small'.
font_size_style_values : '8pt,10pt,12pt,14pt,18pt,24pt,36pt',
// The following line enables source formatting to make HTML editing easier.
apply_source_formatting : true

Now attach the CSS styling to outgoing emails by inserting the following in ‘/modules/Emails/Email.php‘:

$body = 
	"<style>" .
	file_get_contents('include/javascript/tiny_mce/themes/advanced/skins/default/content.css') .
	'</style><div class="email">' .
	$body . 
	'</div>';

Do this around line 1984, just after the following line:

$body = from_html(wordwrap($this->description_html, 996));

This attaches the CSS styling inline (ie. inside the <style /> tags) and wraps the entire email in the <div class=”email” /> container.

Do some testing and you should now find your outgoing emails correctly match what you saw in the compose window, giving you the full WYSIWYG experience!

* Note: CSS support varies heavily between email clients. A comprehensive list of which CSS rules are supported in each client can be found here: Guide to CSS Support in Email.