Tag Archives: windows powershell

Exchange – Delegating Management tasks using PowerShell

As is always the case, things to write about come along all at once. Here’s another little administrative thing I had to read up on and piece together, so I’m posting it as a note to forgetful future me!

I had to find out how to delegate a set of Exchange permissions to create and manage mail users, without allowing the same users to remove things. This sounded like a problem uniquely suited to the powers of the Exchange Management Shell.

To manage Exchange permissions like this, you must be a member of the built-in role group ‘Organization Management‘, which will grant you the permission to see and run these cmdlets.

I started by creating an Exchange role group, which is an Active Directory (AD) security group that will provide the new delegated rights set. Role groups can be created using the cmdlet New-RoleGroup. To see an example of an existing role group, the Get-RoleGroup command will get you started (Output edited for clarity):

Get-RoleGroup | Select-Object -First 1 | Format-List

ManagedBy       : {contoso.test/Microsoft Exchange Security Groups/Organization Management}
RoleAssignments : {Active Directory Permissions-Organization Management-Delegating...}
Roles           : {Active Directory Permissions, Cmdlet Extension Agents...}
Members         : {contoso.test/contoso/Admins/Users/TestAdmin, contoso.test/Users/Administrator}
SamAccountName  : Organization Management
Description     : Members of this management role group have permissions to manage Exchange objects and their properties in the Exchange organization. Members can also delegate role groups and management roles in the organization. This role group shouldn't be deleted.
RoleGroupType   : Standard
Name            : Organization Management

You can create the new role group with a command like this:

New-RoleGroup -Name "Helpdesk Mail User Management" -samAccountName "Helpdesk Mail User Management" -Description "Members of this role group have the ability to create and manage Exchange user objects."

When you look at the group again using Get-RoleGroup, you’ll notice that there are two attributes that are empty compared to the existing groups, ‘Roles’ and ‘RoleAssignments’. These are the attributes that will contain the references to the rights we need our group to have.

Now we have a role group (with no permissions!), we next need to find out and set up the permissions sets, or management roles, we need. Some of this is found out using documentation (under Management role types), but a lot of it is working out what PowerShell command (or commands) an action boils down to and using that to scope your management role.

You can discover this by first finding out what roles contain a specific cmdlet the user will need to do their job:

Get-ManagementRole | Get-ManagementRoleEntry | Where-Object {$_.Name -eq "New-Mailbox"}

The next step is finding out how good a fit that role would be as a base to the custom role by seeing all the cmdlets that role contains. It appears that picking a role with more than you need, then reducing it down is the way to go, as you cannot add entries that don’t exist in the parent role:

Get-ManagementRole "Mail Recipient Creation" | Get-ManagementRoleEntry

Once you’ve planned the cmdlets you’ll need and the roles you can copy and tweak to your satisfaction, you can copy an existing management role:

Get-ManagementRole "Mail Recipient Creation" | New-ManagementRole "Mail Recipient Creation-NoDelete"

To tweak you new management role, you can use the cmdlets we’ve already explored, then filter it with Where-Object:

Get-ManagementRole "Mail Recipient Creation-NoDelete" | Get-ManagementRoleEntry | Where-Object {$_.Name -like "Remove-*"}

Once we’ve discovered the exact cmdlets we need to remove from our new management role, we can use Remove-ManagementRoleEntry as part of the pipeline to get the job done.

Get-ManagementRole "Mail Recipient Creation-NoDelete" | Get-ManagementRoleEntry | Where-Object {$_.Name -like "Remove-*"} | Remove-ManagementRoleEntry

Remember not to be too crazy with wildcards, as you don’t want to remove the cmdlets you need!

Now we have all our management roles sorted out, we can add our new management roles to the security group, so they’ll take effect.

New-ManagementRoleAssignment -SecurityGroup "Helpdesk Mail User Management" -Role "Mail Recipient Creation-NoDelete"

And that’s it! You can add multiple roles to the same group to provide the right permissions set and the process isn’t too difficult once you get your head around how it’s all supposed to work. I haven’t covered scoping here, but there’s a lot of information on TechNet to get you started on setting scopes on role assignments.

PowerShell Workflow – Check-Service script

I’ve recently needed to work with some services in a group of computers where only one service can be active at a time. This particular service I needed to work with is a printing service responsible for printing labels in a shared directory. If more than one service is enabled at a time, we get duplicate labels! (It led to a lot of confusion during user testing when a server was rebooted).

To automate the work required to make sure only one service is running when maintenance or other work occurs, I decided to write a script.

The script can be downloaded from here.

I used PowerShell workflow, as this seemed like a good bet for something that would benefit from the parallelism benefits that a workflow provides. The idea for me is to use it as part of a System Center Orchestrator Runbook to run the script on an alert from Operations Manager.

I worked on making the script take parameters for the computers to run against, the service to work on and how many services should be running at any one time.

Hopefully this also helps some people working to learn some of the basics of workflow, I’ll make sure to add some comments in the script to explain parts of it. Some things certainly confused me for a little while till I got things working!

Microsoft Dynamics AX 2012 – Importing and exporting users with PowerShell

Over the past couple of months I’ve occasionally been working with Microsoft Dynamics AX 2012 and moving model and data sets between different environments.

Once of the downsides to this is overwriting the user and role memberships at the destination. To combat this, I had two options, the AX Data Import/eXport Framework (DIXF), or the AX PowerShell module. I think you can guess which one I went for!

Unfortunately the AX module need to be loaded in a wonderfully manual way and there are a lot of features not provided. The cmdlets even have a horrible lack of support for the very things that make PowerShell so great, like pipelining!

Even lacking these things, it’s still PowerShell, so I soldiered on. It took a little while and some features still have to be implemented, but the two scripts allow users to be imported and exported to/from a CSV, which is good enough to release for a first version.

The two scripts can be downloaded from GitHub.

There are also some features I’ll implement if I get the time, such as complete overwrite on import and support for importing/exporting user data from remote servers.

SCCM 2012 R2 – Operating System deployment when on mains power only

It’s a quick little script I just had to write, after my testing today ran into the minor issue of a flat battery… halfway through the Operating System Deployment (OSD) process.

It’s a little PowerShell script, very similar to the last one that just pops up a box asking you to plug-in the laptop if you are running on battery. I haven’t put much in the way of validation that the device is actually a laptop with a battery, but since my OSD task sequences have a laptop/desktop divide, it’s not too much of a problem!

Here’s the script, the setup instructions are similar to the earlier script, with a different name and a call to a batch file instead of the ServiceUI command.

The batch script contains the command to run ServiceUI, after deciding which copy to run the PowerShell script with, based on the boot image architecture (x86/x64). I’ve put this in at the beginning of the task sequence, once the laptop has booted to the boot image, so we can get the user input or error states dealt with up front.

SCCM 2012 R2 – Validating and setting OSDComputerName with PowerShell

I’ve recently been doing some work with System Center Configuration Manager (SCCM) 2012 R2 recently and I was interested in validating a computer name supplied during an Operating System Deployment (OSD) task sequence before actually attempting to set it and possibly causing an error (with the computer name being too long, for example). Since that sounds like a job for PowerShell, I immediately had a look and found a reasonable solution that almost fit my needs.

As an aside to this, I’m not currently using the Microsoft Deployment Toolkit (MDT) in any real way, however my solution does use a component of it in order to display the PowerShell script to the user. This gave me a good excuse to run through it and start to check it out with the idea of using it more down the line.

The solution I found that almost did what I wanted can be found here (I’ve contributed my alterations there too in the comments. Thanks very much to Nickolaj for his script, as it saved me a fair bit of work!

To run the script, a few things have to be done first (Instructions with screenshots can be found in Nickolaj’s post on scconfigmgr.com.

  • Add the ‘WinPE-NetFx’ and ‘WinPE-Powershell’ features to the boot image you will be using with the OSD. (in “Boot Images > Boot image > Properties > Optional components”)
  • Download a copy of MDT that matches the boot image architecture you want (x86/x64), then extract the ServiceUI.exe file from it, usually located at “%ProgramFiles%\Microsoft Deployment Toolkit\Templates\Distribution\Tools”
  • Create an SCCM package containing the script, plus ServiceUI, but don’t create a program for it, as we’ll deal with that bit when adding it to the task sequence.
  • Add a ‘Run Command Line’ task in your task sequence, then use the package created  in the previous step, along with a command line like:
ServiceUI.exe -process:TSProgressUI.exe %SYSTEMROOT%\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File MYSCRIPTFILENAME.ps1
After testing the script and running it, there were a couple of things I saw that could be improved:
  • First was the ability to hit enter and have that correspond to the OK button. It’s  minor thing, but makes a massive difference to the user experience!
  • Next, was the validation/correction of the computername. The original script will silently strip out invalid characters, which may leave some wondering why the computer name appears differently to how it was originally typed.

I started with making the enter button correspond to the OK button. I did this by adding the following code just before the call to load the form:

$Form.KeyPreview = $True
$Form.Add_KeyDown({if ($_.KeyCode -eq "Enter"){Set-OSDComputerName}})

Next, I wanted to remove the silent removal of user input and make it obvious to the user that they had entered an invalid computer name. I did this by re-using the existing ErrorProvider and moving the validation code to another clause in the if statement.

This meant that instead of having:

else {
  $OSDComputerName = $TBComputerName.Text.Replace("[","").Replace("]","").Replace(":","").Replace(";","").Replace("|","").Replace("=","").Replace("+","").Replace("*","").Replace("?","").Replace("<","").Replace(">","").Replace("/","").Replace("\","").Replace(",","")
  $TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment 
  $TSEnv.Value("OSDComputerName") = "$($OSDComputerName)"
  $Form.Close()
}

We end up with something slightly different (ignoring the use of a Regular Expression to validate the computer name instead of a multiple string.Replace())

#Validation Rule for computer names.
elseif ($TBComputerName.Text -match "^[-_]|[^a-zA-Z0-9-_]")
{
  $ErrorProvider.SetError($GBComputerName, "Computer name invalid, please correct the computer name.")
}
 
else 
{
  $OSDComputerName = $TBComputerName.Text.ToUpper()
  $TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment
  $TSEnv.Value("OSDComputerName") = "$($OSDComputerName)"
  $Form.Close()
}

As you can see, this makes the script a little easier to read, which always bodes well for improvements in the future. One thing that still slightly annoys me is the format of the if elseif elseif else. This is quite close to being made a switch statement, but it’s OK until I find the need to add another clause. I’d also like to find a way to remove the MDT dependency of ServiceUI.exe, as this requires a different SCCM package or invocation based on architecture (x86/x64). However, this may not be possible due to the way the OSD task sequence works.

Here is the current script I’m using in full. Please let me know if you have any improvements you can suggest, as it’s always a good day to learn!

Exchange 2003, PFDAVAdmin and PowerShell

I’ve been working with Exchange 2003 a bit recently, as part of a migration to Office 365. Most of the work has been around getting permission data, mailbox sizes and some other related data.

As part of that, I’ve written a couple of PowerShell scripts to grab some information we needed for the migration. The first is a script to get data from Exchange and AD in a 2003 domain using WMI. The second is a script to parse and output permission data from a PFDAVAdmin export in a more usable format.

I’ve put the two scripts on GitHub in my miscellaneous repository, under the PowerShell folder. Hopefully they come in useful to anyone else needing to make more sense of PFDAVAdmin exports, or pull mailbox data from Exchange 2003.

GitHub Gists and other snippets

I’m making more of an effort to post useful snippets of PowerShell and other stuff, like custom ADMX templates to either my GitHub Gists, or to a GitHub repository I’ve set up for miscellaneous bits and bobs.

As I’ve improved with PowerShell, it’s become easier to write generalised scripts, rather than highly targeted ones, so that I can solve similar problems, or share pieces of scripts around more easily.

If you’d like to learn more about Windows PowerShell check out PowerShell.org and the PowerScripting Podcast, they are nice friendly places that are easy to navigate and full to the brim with good content.