Convert Camel Case to space delimited Display Name with PowerShell

I’m writing a very rudimentary script that has a need to convert something like “groundFloorMeetingRoom” to “Ground Floor Meeting Room”. Rather than prompt the user to enter this, I decided it’d be easier to just get the script to do it. This turned out to be a fun little exercise, resulting in the CamelCaseToDisplayName function below. Hopefully it can help someone!

function CamelCaseToDisplayName ([string]$inString) {
$newString = ""
$stringChars = $inString.GetEnumerator()
$charIndex = 0
foreach ($char in $stringChars) {
# If upper and not first character, add a space
if ([char]::IsUpper($char) -eq "True" -and $charIndex -gt 0) {
$newString = $newString + " " + $char.ToString()
} elseif ($charIndex -eq 0) {
# If the first character, make it a capital always
$newString = $newString + $char.ToString().ToUpper()
} else {
$newString = $newString + $char.ToString()
}
$charIndex++
}
$newString
}

It’s pretty simple to run, just throw something like this in your script:

$newName = CamelCaseToDisplayName “groundFloorMeetingRoom”

How to use a Domain Controller as an Exchange 2013 DAG Witness Server (Don’t)

If you’re setting up Exchange 2013 in a lab, you may have a requirement to use a domain controller as a File Share Witness (FSW) host.

Obligatory disclaimer: While this is definitely not recommended practise in a production environment, and may have undesirable results, it will probably work. I highly doubt Microsoft support this, though I have been unable to find any concrete evidence on it (frankly, it’s such terrible practise they shouldn’t have to publicise advice against it). If you can come up with a method to avoid following this guide in production, I implore you to do so.

The File Share Witness is used as the winning vote when your DAG has an even number of hosts – the same principle as the quorum drive in a Failover Cluster. This is a file server that all DAG members can read and write (but cannot be a DAG member for obvious reasons).

If you just try to create a DAG and use a domain controller as a FSW, you’ll get this error message:

image

Checking the log file gives the following access denied message, which is less than helpful:

[2013-04-23T23:15:32] WriteError! Exception = System.Management.ManagementException: Access denied
   at System.Management.ManagementException.ThrowWithExtendedInfo(ManagementStatus errorCode)
   at System.Management.ManagementScope.InitializeGuts(Object o)
   at System.Management.ManagementScope.Initialize()
   at Microsoft.Exchange.Management.Common.WmiWrapper.TryGetSystemDrive(String computerFqdn)
   at Microsoft.Exchange.Management.Common.FileShareWitness.Initialize()
   at Microsoft.Exchange.Management.SystemConfigurationTasks.NewDatabaseAvailabilityGroup.InternalValidate()

image

What’s happening here is that the Exchange server is trying to create a file share on the FSW host, in this case E15DC1. In order to allow this functionality on a domain controller, you must add it to the Exchange Trusted Subsystem group. This is an Active Directory group used internally by Exchange for reading/writing this share, amongst other things. Typically it will only contain Exchange Servers, but go ahead and add your file share witness host to it as well:

 

image

Now comes the bit that makes the security part of me cringe. Exchange Trusted Subsystem (i.e. your Exchange servers) need to be able to create shares on this server and read/write them. As a domain controller has no local security groups, you need to apply this change directory-wide. Add Exchange Trusted Subsystem to your Administrators group:

 

What you’ve done here is made every Exchange server a domain admin. This means that anything running in the context of an Exchange server computer’s user account (E15MB1$, E15MB2$ etc) has full rights over the domain. Do not do this in production!

After giving your DC a reboot (to update its security group membership), Exchange Trusted Subsystem will be able to create shares on it, and your DAG will be able to be created successfully:

image

Add some member servers and Bob’s your uncle. DO NOT DO THIS IN PRODUCTION! I cannot say it enough.

Exchange Server 2013 PowerShell Guide

Today Paul Cunningham announced to the world an exciting new guide that is in the process of being written. Paul and I are working together to produce the (working title) Exchange Server 2013 PowerShell Guide. This is exciting for me as it will be the first ebook I’ve worked on, and it’s an honour to be writing alongside the ebook powerhouse that is Exchange Server Pro.

Exchange 2013 brings about some significant changes, not least of all on the automation front. Exchange 2013 has dropped the “show script” image button that Exchange 2010 administrators are familiar with, primarily due to the lack of Exchange Management Console. What this means is that PowerShell is a lot less discoverable than it used to be, in that there’s no “how do I do this in PowerShell?” button for the beginner to use as a kickstart. We aim to bridge this gap in the guide, allowing administrators new to Exchange 2013, Windows PowerShell or both to get their head around just how it all fits together.

Throwing in a mix of PowerShell basics and Exchange Server 2013 administration techniques, this will be a great opportunity for the beginner or advanced administrator to begin or upgrade their skillset.

For more details, be sure to check out Paul’s announcement and sign up to the Exchange Server Pro newsletter for updates.

Check out some of Paul’s previous ebooks including the Exchange Server 2003 to 2010 and 2007 to 2010 migration guides over on Exchange Server Pro.

How to Retrieve Mac OS X 10.8 Active Directory Computer Account Password

Active Directory bound Mac OS X computers traditionally stored the computer account credentials in /Library/Preferences/DirectoryService/ActiveDirectory.plist. As of OS X 10.7, this has been moved to the (theoretically) more secure System Keychain. Because of this, a slightly different method has to be employed to extract the computer account password. Fortunately, this is easier than the old plist method. Simply run the following command in Terminal as root (or any sudoer):

security find-generic-password –sw “/Active Directory/MARGIESTRAVEL” /Library/Keychains/System.keychain

This command broken down:

security is the application for accessing keychain information. It is automatically decrypted and presented in a somewhat readable format as though you were using Keychain Access.app.

find-generic-password retrieves the contents of a Keychain item

-w is an option that tells security to only return the password, and to StdOut. By default, security returns generic info to StdOut and returns the password to StdErr. –w “fixes” this.

-s is an option that tells security to return the item of service type <string>.

“/Active Directory/MARGIESTRAVEL” is the name of the keychain item in string format. Obviously this is the Directory Service path to the domain (you can verify by running dscl).

/Library/Keychains/System.keychain is the filesystem path to the System keychain itself.

If you want your script to be redistributable (hint: you do), you can do the following to get the name of the computers’ domain:

dscl localhost –list ”/Active Directory”

This will return the name of the computer’s domain. You could update the command above to implement this like so:

security find-generic-password –w -s “/Active Directory/$(dscl localhost –list '”/Active Directory”)” /Library/Keychains/System.keychain

All we’re doing here is replacing the “MARGIESTRAVEL” component of the name of the keychain item with the command that asks dscl for the name of the computer’s domain. Easy!

P.S. here’s how to get the AD computer account name as well. Doesn’t deserve a blog post, but an interesting little snippet:

security find-generic-password -s "/Active Directory/MARGIESTRAVEL" /Library/Keychains/System.keychain | grep -m 1 "acct" | sed -e 's/"acct"\<blob\>\="//' -e 's/"//' | tr -d ' '

(This one just returns the whole keychain item and looks for the first line containing “Acct”. It then removes all the useless info around the outside of the computer name.

How to perform an unattended install of the SCCM 2012 Client on Mac OS X

Installing the Configuration Manager client on Mac OS X is a new feature of SCCM 2012 SP1. Unfortunately the installation process is nowhere near as easy as installing for a PC. The steps go something like this:

1. Download a DMG of the client installer

2. Run the install script

3. Run the script to get a certificate from the CA

Fortunately, these steps are quite easy to script.

Before you proceed any further, be sure that manual deployments of the Mac client work. James Bannan has an excellent guide on this over on his website.

In this instance, we’ll assume the script is being run as part of an automated deployment, so it would be useful to have the dmg file hosted somewhere, as well as credentials that can request the certificate. For this, I’ve created a directory in my SCCM 2012 SP1 MP’s Default Web Site called “MacClient”, with contents as follows:

PS C:\> gci C:\inetpub\wwwroot\MacClient
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 10/01/2013 10:53 AM 50 credentials.txt
-a--- 6/12/2012 5:39 PM 4776423 macclient-5.0.0.7804.1000.dmg
-a--- 10/01/2013 9:29 AM 29 MacClient-dmg-latest.txt

This is accessible at https://sccm.margiestravel.com/MacClient/. I had to add a MIME type for .DMG so that IIS would allow it to be downloaded. This is a simple addition to the <system.webServer> section of the web.config file in this directory:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<staticContent>
<mimeMap fileExtension=".dmg" mimeType="file/download" />
</staticContent>
<directoryBrowse enabled="true" />
</system.webServer>
</configuration>

Credentials.txt is a two-line text file, the first line of which contains a username in the format DOMAIN\Username and the second a password. For example:

MARGIESTRAVEL\SccmCertDeployment
Pa$$w0rd

The MacClient-dmg-latest.txt file is called by the client script. This text file contains the just the filename of the latest version of the SCCM client DMG, located in the same directory. This means that you can keep older installers in place for whatever reason, while the automatic script will be sure to grab the latest version. Alongside this is “macclient-5.0.0.7804.1000.dmg”, the DMG file containing the Mac Client for SCCM 2012 SP1.

As you can see, the majority of the operation is performed server-side, which means this script can be built into your OS X deployment/post-image procedures and *should* never need to be updated. All you have to do is drop a new DMG in, update the text file, and occasionally you’ll likely want to change the credentials that request the certificate. (I know typically the computer’s user would request the certificate themselves with their own AD credentials, but in this case I’m using the same set of credentials for everyone. The script could certainly be modified to prompt for a set of AD credentials from the user)

Here’s a copy of the script. Lines 18-22 are the only ones that should require changing. Here’s a brief description of what each variable does:

appDistributionSite is the base URL of the folder containing the credentials.txt and MacClient-dmg-latest.txt files.

configMgrServer is the FQDN of your SCCM 2012 SP1 Management Point that’s configured for internet access.

scriptVersion is just the version number of this script. You may wish to increment this if you ever make changes to the script, as scriptVersion is reported to the SCCM server as the client’s User Agent. You can view this in your IIS logs.

userAgent is a string presented to the web server when downloading files.

workingDirectory defines where on the client files will be placed while installing the SCCM client. The script will create this folder if it does not exist. The default is ~/CMInstallTemp.

You can download a zip file of the script and text files ready to go. You’ll just have to grab the DMG file from your SCCM 2012 SP1 install media and place it on your web server with them.