Deploying Operating systems with MDT, SCCM, Orchestrator and SCSM – part 6

I intend this to be a series of blog posts about my experience in implementing end to end OSD solution. I will be writing about my lab implementation, as production version has much unneeded clutter that would just confuse the whole blog post.

I thought this blog series would be split in following posts:

  1. Intro
  2. Lab setup
  3. MDT
  4. SCCM
  5. Intel AMT
  6. Orchestrator
  7. SCSM
  8. Bringing it all together
  9. Recap

We are now able to deploy computers using MDT and SCCM, deploy specific operating system to a known computer in SCCM, and deploy New, Replace and Refresh scenarios. But all the work has to be done manually. At this point I started to look around for a solution that would enable me to automate all the steps needed to deploy computers, and that would also enable me to have a self service portal, so I would “never” have to lay my hands on this process.

One solution that I found at that time was to use System Center Orchestrator for automation part and System center Service Manager for the self service portal. This is what I built half a year ago and is a red line for this blog series. This is not a light weight solution, as it requires at least 3 servers just to do automation and self service portal, and if you only think of using it for OSD, there are probably better solutions for you, I will discuss them at the end. However, if you already have System Center license, then it comes at no additional license cost to you…

Anyway, let’s get into Orchestrator. First, you need to install it.

You will need to prepare the following:

  • Minimum of one server, I user 2012 R2
  • One service user, with which Orchestrator will run on server
  • Connector users Orchestrator will use to connect to external tools, with correct permissions.

When you have all this, you are ready to install Orchestrator.

Insert your Orchestrator installation media and run Setup.exe and follow the wizard.

I installed all features on one server.

orch1

Then enter credentials for service account and test them. On the next screen enter database server name and instance. Make sure you have enough permissions on the database server. More info here: https://technet.microsoft.com/en-US/library/hh420367.aspx

On the next screen you can either user existing database or create a new one. Then select group which will administrative permissions on your Orchestrator installation.

Remember the ports you select on this next page, if you change them from default.

After you finish the installation, you are ready to user Orchestrator.

 

Now when I first started with automating OSD with Orchestrator, I thought about doing everything using runbooks and activities. After a while I figured out that not everything can be done with available activities, be it built in, or those from additional Integration Packs (OIP). I always ended up using PowerShell for one or another task, for example MDT. I also figured out that Orchestrator does not really like PowerShell. 🙂 I had to use Run .Net Script activity, or play around with PowerShell OIP.

So I set up writing my own OIP for missing features. And I slowly created MDT OIP, and a few other bells and whistles that were missing for this specific task I wanted to do. Then as a mental exercise I created PowerShell scripts that did the needed steps. I ended up running them with Run .Net Script. This was kind of OK, but then I have re-written and re-think the whole thing once again, and created one script that did all necessary steps in one go. In the end I created PowerShell Module for Computer Management which script being run from Orchestrator calls with parameters you enter.

It was quite a journey for me and I really learned a lot during this time. It is also one of the reasons it has taken almost 6 months to get to this point in blog series. I was always fine tuning the script, or module, or OIP to the point where I had a working solution in my development environment but I was adding new ways of achieving the same thing, that seemed better to me, at least at the time.. 🙂

So this is how it ended up looking in a runbook.

orch2

Really simple. I just get the data from Initialize Data, which I end up passing to Run command, like that:

orch3

Now I pass on quite a lot of information, because of the way I do permissions testing, Computer name structure, … We have quite a lot of rules there we have to adhere to. This also means I have a bit of a problem sharing all my scripts and modules with you… I will have to, you guessed it, re-write them all. 🙂 I will do it as soon as time permits and then release them in the wild, so you guys can use them as well. I will put the link to GIT here once I do that.

 

So, now we have Orchestrator installed, and hopefully I will be able to share the scripts I use with you soon, so then you have everything automated as well. Next step, creating a self service portal, where users, or HD guys, can request OSD for a computer.

Edit:

I have managed to create a quick sample code for Computer Management. It is a smaller version of what I actually created, I just omitted proprietary information and functions that check for permissions and computer name structure. The code is on GitHub, my first try with GitHub 🙂

https://github.com/djanny22/PowerShell/blob/master/JANComputerManagement.psm1

Automating DCOM ACL with PowerShell

Sometimes you need to set explicit permissions on DCOM objects. You can do this using dcomcnfg.exe. With dcomcnfg.exe you can set permissions on all DCOM objects on a computer. However, this is doing it manually. 🙂 If you ever need to automate this step, you can do it using PowerShell, and here is how. Please note you have to run PowerShell as Administrator.

dcomcnfg

Automating DCOM ACL with PowerShell

There are 5 steps to configure DCOM ACL.

1.) Get WMI object

2.) Get Descriptor

3.) Create Trustee and assign it rights

4.) Add Trustee to Descriptor

5.) Set WMI object

In step one, we get WMI object for DCOM application we want to set permissions. In below example, we get settings for Messaging application

$wmi = Get-WmiObject -Class Win32_DCOMApplicationSetting -Filter ‘caption=”Messages”‘ -EnableAllPrivileges

In step two we get current security descriptor for this object, so we can add permissions to existing set. We can get and set permissions for all 3 types

$descL = $wmi.GetLaunchSecurityDescriptor().descriptor
$descA = $wmi.GetAccessSecurityDescriptor().descriptor
$descC = $wmi.GetConfigurationSecurityDescriptor().descriptor

Image from GUI:

dcomcnfgSec

In step three we create our own trustee object, which we will use to assign rights to. It consists of Domain, username and permissions we would like to assign to it. In this example we will set all permissions to allow to user object Interactive.

$trusteeObj = ([wmiclass]’Win32_Trustee’).psbase.CreateInstance()
$trusteeObj.Domain = “NT authority”
$trusteeObj.Name = “Interactive”

$ace = ([wmiclass]’Win32_ACE’).psbase.CreateInstance()
$ace.AccessMask = 31
$ace.trustee = $trusteeObj

If you need to set different permissions then in example above, you can get AccesssMask values by manually setting permissions in GUI as you need them and then read them using PowerShell. In step two we got current descriptor, from which we can read current permissions.

First we need to get DACL list:

$descL.[X].DACL

in this object you have current Trustee and it’s AccessMask.

From here on it is very simple…

In step four we add our object we created in step 3 to descriptor

$descL.DACL += [System.Management.ManagementBaseObject]$ace
$descA.DACL += [System.Management.ManagementBaseObject]$ace
$descC.DACL += [System.Management.ManagementBaseObject]$ace

And in step five we write is back using WMI.

$wmi.SetLaunchSecurityDescriptor($descL)
$wmi.SetAccessSecurityDescriptor($descA)
$wmi.SetConfigurationSecurityDescriptor($descC)

We can see the changes we made using dcomcnfg.exe or PowerShell

dcomcnfgSec2

Again, do not forget to run PowerShell as Administrator! 😉

Code is available for download on TechNet:

https://gallery.technet.microsoft.com/Set-DCOM-ACL-with-650fa48d

Hope this helps you.

Delete Disabled Profiles from Computers

Your users are connecting to terminal server, so they can use an application, and everything works just fine, until one day, a user can’t connect. You swing into action and find out, that the problem lies on your hard drive, or better yet, lack of it. You ran out of disk space on your terminal server. You check what is taking up most of the disk space, and you see there are dozens and dozens of user profile folders. now, you could go, and delete just the folders, but that results in users getting temp profiles. The other option is, to go to advanced settings of your system, and delete profiles from there, But how do you know which ones to delete?

UserProfiles

You could delete just the biggest ones, but the User Profiles dialog does not allow you to make any kind of sorting. The other thing you could do, this being a terminal server, is delete all profiles, but one by one? Who wants to do this. You guessed it, a script.

I wrote a script that  does just that. It is available on Technet Gallery, https://gallery.technet.microsoft.com/Delete-Disabled-profiles-06d4e82a.

To be able to run it, you must have administrator privileges on target computer and installed Active Directory module on computer running it.

It only works on Windows Vista/Server 2008 and above, as before that, the WMI class I use, did not exist.

Enjoy it, and save your disk space. 🙂

Powershell to sanitize GPO

Quick ways to sanitize GPOs with Powershell.

Did you ever wonder how many GPOs do you have that do not have any links?

GPOLinking

Or if there are any users that were assigned Security Filterings on GPO, but have since been deleted?

 

GPOFiltering

 

Here is are two quick “scripts”, that will find you just that, so you can further investigate and “sanitize” your Group Policy Objects.

# Get all GPO that are not linked to anything
Get-GPOReport -all -ReportType xml | %{([xml]$_).gpo | select name,@{n="SOMName";e={$_.LinksTo | % {$_.SOMName}}},@{n="SOMPath";e={$_.LinksTo | %{$_.SOMPath}}} | % {if($_.SOMPath -eq $null){$_}}}

#
# Get all GPO objects, that have permissions set to deleted users (No DisplayName, just SID)
$gpo = Get-GPO -all; $gpoo =@();$gpo | % {$aa = $_;$_| get-gppermissions -all | %{ if($_.trustee.name -eq $null){if($gp.contains($aa.DisplayName)){} else{$gp += $aa.DisplayName} } }}; $gp