Tuesday, August 11, 2015

Agile Legacy System Analysis and Integration Modeling

Came across this article in Code Magazine and found that it also applies to the identity integration work we do with the Synchronization Service (metadirectory, provisioning). 

Agile Legacy System Analysis and Integration Modeling

I've been a big fan of Agile for the development and deployment work on engagements but this article brings Agile into the planning and modeling, which is a cool idea.


Monday, May 11, 2015

Microsoft MVP Virtual Conference

Pretty excited to be doing a presentation on PowerShell Desired State Configuration this week for the Microsoft MVP Virtual Conference: PowerShell Desired State Configuration (DSC) - Custom Resource Development

The Microsoft MVP Virtual Conference is a free event that Microsoft and the MVPs are putting on, May 14th & 15th.  Join Microsoft MVPs from the Americas’ region as they share their knowledge and real-world expertise during a free event, the MVP Virtual Conference.

The conference will showcase 95 sessions of content for IT Pros, Developers and Consumer experts designed to help you navigate life in a mobile-first, cloud-first world.  Microsoft’s Corporate Vice President of Developer Platform, Steve Guggenheimer, will be on hand to deliver the opening Key Note Address.

Why attend MVP V-Conf? The conference will have 5 tracks, IT Pro English, Dev English, Consumer English, Portuguese mixed sessions & Spanish mixed sessions, there is something for everyone! Learn from the best and brightest MVPs in the tech world today and develop some great skills!

Be sure to register quickly to hold your spot and tell your friends & colleagues.

The conference will be widely covered on social media, you can join the conversation by following @MVPAward and using the hashtag #MVPvConf.

Tuesday, May 05, 2015

Using ConvertFrom-Json to View MIM Reporting Log Detail

Been playing with the new MIM reporting feature which I think is really cool.  The feature logs events to an event log named ‘Identity Manager Request Log’.  The log can be viewed with this handy PowerShell command:

Get-EventLog -LogName 'Identity Manager Request Log'

    Index Time          EntryType   Source                 InstanceID Message                                                                                           

   ----- ----          ---------   ------                 ---------- -------                                                                                           

       5 May 05 15:48  Information Microsoft.Identit...         4121 {"HybridObjectID":"851ff609-9383-4ad6-9e1e-8578e6ef12f3","ObjectType":"Request","Creator":{"Hybr...

       4 May 05 15:47  Information Microsoft.Identit...         4121 {"HybridObjectID":"322fa4e4-036a-4999-88b4-62f68c7daefa","ObjectType":"Request","Creator":{"Hybr...

       3 May 04 19:05  Information Microsoft.Identit...         4121 {"HybridObjectID":"a54f326c-e816-4cd9-84a0-e95eae0bb6db","ObjectType":"Request","Creator":{"Hybr...

       2 May 04 19:02  Information Microsoft.Identit...         4121 {"HybridObjectID":"c586ca82-a2ab-4a42-9cf0-b1d915073e58","ObjectType":"Request","Creator":{"Hybr...

       1 May 04 18:47  Information Microsoft.Identit...         4121 {"HybridObjectID":"56c3d42b-6540-4a26-8795-ea8006e239a5","ObjectType":"Request","Creator":{"Hybr...

 

 

Looking at the event message property it isn’t very easy to read, but it does contain a ton of detail:

Event Message

{"HybridObjectID":"851ff609-9383-4ad6-9e1e-8578e6ef12f3","ObjectType":"Request","Creator":{"HybridObjectID":"95604f19-cc4b-453b-a69b-82086027408b","CreatedTime":"Apr 30 2015  6:48PM","Creator":"2340","DomainConfiguration":"2730","ObjectID":"13418","AccountName":"TieDomi","Description":"Have any grapes?","DisplayName":"Tie Domi","Domain":"CMMIM001","Email":"TieDomi@cmmim001.ca","EmployeeType":"Contractor","FirstName":"Tie","JobTitle":"Enforcer","LastName":"Domi","ObjectType":"Person"},"Operation":"Put","Target":{"HybridObjectID":"fafff0d3-0e63-4084-9253-d74855ed2275","MembershipLocked":"0","CreatedTime":"Apr 30 2015  7:55PM","ComputedMember":["2340","13418"],"Creator":"2340","DisplayedOwner":"2340","ExplicitMember":["2340","13418"],"Owner":"2340","DomainConfiguration":"2730","ObjectID":"13426","DisplayName":"Leafs Fans","Domain":"cmmim001","MailNickname":"LeafsFans","MembershipAddWorkflow":"None","ObjectType":"Group","Scope":"Universal","Type":"Distribution"},"RequestStatus":"Completed","ManagementPolicy":[{"HybridObjectID":"fc53fd3c-92fa-4235-bbb7-2b21df6b98a0","Disabled":"0","GrantRight":"1","CreatedTime":"Apr 30 2015  8:17AM","PrincipalSet":"2733","ResourceCurrentSet":"2830","ResourceFinalSet":"2830","ObjectID":"2858","ActionParameter":"ExplicitMember","ActionType":["Add","Remove"],"Description":"Distribution list management: Users can add or remove any members of groups that don't require owner approval","DisplayName":"Distribution list management: Users can add or remove any members of groups that don't require owner approval","ObjectType":"ManagementPolicyRule","ManagementPolicyRuleType":"Request"},{"HybridObjectID":"5d94d491-e7dc-4da3-8026-fb125cfb3f2a","Disabled":"0","GrantRight":"0","CreatedTime":"Apr 30 2015  8:17AM","AuthorizationWorkflowDefinition":"2485","PrincipalSet":"2835","ResourceCurrentSet":"2836","ResourceFinalSet":"2836","ObjectID":"2913","ActionParameter":"ExplicitMember","ActionType":"Add","Description":"Group management workflow: Validate requestor on add member to open group","DisplayName":"Group management workflow: Validate requestor on add member to open group","ObjectType":"ManagementPolicyRule","ManagementPolicyRuleType":"Request"}],"AuthorizationWorkflowInstance":[{"HybridObjectID":"b85a56c8-cd08-408f-9464-3e2860177ce9","CreatedTime":"May  5 2015  3:48PM","WorkflowDefinition":"2485","Creator":"13418","Requestor":"13418","Target":"13426","Request":"33424","ObjectID":"33425","DisplayName":"Requestor Validation Without Owner Authorization","ObjectType":"WorkflowInstance","WorkflowStatus":"Completed"}],"DisplayName":"Update to Group:  'Leafs Fans' Request","CreatedTime":"5/5/2015 3:48:19 PM","TargetObjectType":"Group","CommittedTime":"5/5/2015 3:48:26 PM","RequestParameter":[{"Calculated":"false","PropertyName":"ExplicitMember","Value":{"HybridObjectID":"95604f19-cc4b-453b-a69b-82086027408b","CreatedTime":"Apr 30 2015  6:48PM","Creator":"2340","DomainConfiguration":"2730","ObjectID":"13418","AccountName":"TieDomi","Description":"Have any grapes?","DisplayName":"Tie Domi","Domain":"CMMIM001","Email":"TieDomi@cmmim001.ca","EmployeeType":"Contractor","FirstName":"Tie","JobTitle":"Enforcer","LastName":"Domi","ObjectType":"Person"},"Operation":"Create","Mode":"Add"}]}

Turns out that is just a pile of JSON which we can easily turn back into a useful object, like this:

Get-EventLog -LogName 'Identity Manager Request Log' -Newest 1 |

Select-Object -ExpandProperty Message |

ConvertFrom-Json

 

HybridObjectID                : 851ff609-9383-4ad6-9e1e-8578e6ef12f3

ObjectType                    : Request

Creator                       : @{HybridObjectID=95604f19-cc4b-453b-a69b-82086027408b; CreatedTime=Apr 30 2015  6:48PM; Creator=2340; DomainConfiguration=2730;

                                ObjectID=13418; AccountName=TieDomi; Description=Have any grapes?; DisplayName=Tie Domi; Domain=CMMIM001; Email=TieDomi@cmmim001.ca;

                                EmployeeType=Contractor; FirstName=Tie; JobTitle=Enforcer; LastName=Domi; ObjectType=Person}

Operation                     : Put

Target                        : @{HybridObjectID=fafff0d3-0e63-4084-9253-d74855ed2275; MembershipLocked=0; CreatedTime=Apr 30 2015  7:55PM;

                                ComputedMember=System.Object[]; Creator=2340; DisplayedOwner=2340; ExplicitMember=System.Object[]; Owner=2340;

                                DomainConfiguration=2730; ObjectID=13426; DisplayName=Leafs Fans; Domain=cmmim001; MailNickname=LeafsFans; MembershipAddWorkflow=None;

                                ObjectType=Group; Scope=Universal; Type=Distribution}

RequestStatus                 : Completed

ManagementPolicy              : {@{HybridObjectID=fc53fd3c-92fa-4235-bbb7-2b21df6b98a0; Disabled=0; GrantRight=1; CreatedTime=Apr 30 2015  8:17AM; PrincipalSet=2733;

                                ResourceCurrentSet=2830; ResourceFinalSet=2830; ObjectID=2858; ActionParameter=ExplicitMember; ActionType=System.Object[];

                                Description=Distribution list management: Users can add or remove any members of groups that don't require owner approval;

                                DisplayName=Distribution list management: Users can add or remove any members of groups that don't require owner approval;

                                ObjectType=ManagementPolicyRule; ManagementPolicyRuleType=Request}, @{HybridObjectID=5d94d491-e7dc-4da3-8026-fb125cfb3f2a; Disabled=0;

                                GrantRight=0; CreatedTime=Apr 30 2015  8:17AM; AuthorizationWorkflowDefinition=2485; PrincipalSet=2835; ResourceCurrentSet=2836;

                                ResourceFinalSet=2836; ObjectID=2913; ActionParameter=ExplicitMember; ActionType=Add; Description=Group management workflow: Validate

                                requestor on add member to open group; DisplayName=Group management workflow: Validate requestor on add member to open group;

                                ObjectType=ManagementPolicyRule; ManagementPolicyRuleType=Request}}

AuthorizationWorkflowInstance : {@{HybridObjectID=b85a56c8-cd08-408f-9464-3e2860177ce9; CreatedTime=May  5 2015  3:48PM; WorkflowDefinition=2485; Creator=13418;

                                Requestor=13418; Target=13426; Request=33424; ObjectID=33425; DisplayName=Requestor Validation Without Owner Authorization;

                                ObjectType=WorkflowInstance; WorkflowStatus=Completed}}

DisplayName                   : Update to Group:  'Leafs Fans' Request

CreatedTime                   : 5/5/2015 3:48:19 PM

TargetObjectType              : Group

CommittedTime                 : 5/5/2015 3:48:26 PM

RequestParameter              : {@{Calculated=false; PropertyName=ExplicitMember; Value=; Operation=Create; Mode=Add}}

 

Thursday, April 30, 2015

Using PowerShell to Create Sample AD and MIM Users

OK this blog post is just for me because I expect to have to do this a lot in the coming months as we see more exciting stuff with MIM 2016, and I often read my own blog to retrieve script snippets.

This little snippet creates an Active Directory user object, and the corresponding MIM person object.  This is handy if you just want to get the user into MIM with enough detail on the object for them to be able to logon and view the MIM Portal.

ipmo ActiveDirectory

asnp FimAutomation

ipmo FimPowerShellModule

 

### Create a SecureString for the AccountPassword

$newPassword = ConvertTo-SecureString 'HoofHearted?Icemelted.' -AsPlainText -Force

 

### Use a CSV string for the sample user data

@'

FirstName,LastName,JobTitle

Tie,Domi,Enforcer

Tia,Leoni,Actress

Mats,Sundin,Captain

'@ |

ConvertFrom-Csv |

ForEach-Object {

    ### Construct a couple of strings

    $AccountName = "$($_.FirstName)$($_.LastName)"

    $DisplayName = "$($_.FirstName) $($_.LastName)"

 

    ### Create the AD User

    New-ADUser -Name $AccountName -GivenName $_.FirstName -Surname $_.LastName -SamAccountName $AccountName -DisplayName $DisplayName -Enabled $true -AccountPassword $newPassword

 

    ### Create the MIM Person

    New-FimImportObject -ObjectType Person -State Create -Changes @{

       DisplayName  = $DisplayName

       AccountName  = $AccountName

       FirstName    = $_.FirstName

       Description  = 'Have any grapes?'

       EmployeeType = 'Contractor'

       LastName     = $_.LastName

       JobTitle     = $_.JobTitle

       Domain       = 'LITWARE'

       Email        = "$AccountName@litware.ca"

       ObjectSID    = (Get-ObjectSid -AccountName $AccountName)

    } -ApplyNow

}

 

 

Wednesday, April 29, 2015

Build an Active Directory Forest in Microsoft Azure

Found out late today that I need a Microsoft Identity Manager 2016 (MIM 2016) demo for tomorrow.  Sleep is for pansies, right?

Figured it’d be useful to start automating this in Azure to share the demo load with other demo monkeys so I can get on with riding my bike or playing with my kids like I’m supposed to.

Luckily somebody has done a lot of the work for me, and it works like a charm!

Build an Active Directory Forest in Microsoft Azure

The script at the link above is pretty slick because it starts with a VM image from Azure then installs Active Directory onto it.  It will also create domain-joined member servers and even domain-joined client computers.  In my case I just want a DC and a member server to run MIM.  The script below ran in just minutes, leaving me with a great starting point to do the MIM installation.  Sweet!

### Import the Azure PowerShell Module

ipmo 'C:\Program Files (x86)\Microsoft SDKs\Azure\PowerShell\ServiceManagement\Azure'

 

### Get all my goods (this prompts you to logon with your tenant creds)

Add-AzureAccount

 

### Select a subscription to use

Get-AzureSubscription -SubscriptionName 'Craig Demo' | Select-AzureSubscription

 

### Create a fresh AD Forest with one DC and one Member server

### This cool script came from the Azure Script Center:

### Build an Active Directory Forest in Microsoft Azure

### https://gallery.technet.microsoft.com/scriptcenter/Build-AD-Forest-in-Windows-3118c100

.\Azure_AD_Build.ps1 -ServicePrefix craigSvc -Location 'West US'-AdminUser litAdmin -AdminPassword 'hoofHearted?'-ForestFqdn litware.ca -Domain litware -MemberCount 1 

 

Using a Hashtable in a PowerShell DSC Custom Resource

When creating a new DSC resource property using the DSC resource designer you are allowed to specify the type as ‘Hashtable’.  Though I’ve created a lot of resources I haven’t used a property of this type yet, but today somebody asked me about it.

My first attempt to figure it out was to look at existing resources but I wasn’t able to find any.

My next attempt was to create a sample DSC resource to try it out.  The bad news is that it doesn’t work, at least the generated DSC resource code doesn’t work.  The good news is that it isn’t difficult to make it work.

Check out the snippets!

 

### Create a simple resource with a Hashtable property

New-xDscResource -Name cBar -Path 'C:\Program Files\WindowsPowerShell\Modules\cBar' -Property @(

    New-xDscResourceProperty -Name DisplayName -Type String    -Attribute Key

    New-xDscResourceProperty -Name Hashtable   -Type Hashtable -Attribute Write

)

 

### Edit the generated files

psedit 'C:\Program Files\WindowsPowerShell\Modules\cBar\DSCResources\cBar\cBar.psm1'

psedit 'C:\Program Files\WindowsPowerShell\Modules\cBar\DSCResources\cBar\cBar.schema.mof'

 

### Create an empty PSM1 file for the new module

Set-Content -Value "### Test File" -Path 'C:\Program Files\WindowsPowerShell\Modules\cBar\cBar.psm1' -Encoding UTF8

 

### Create a configuration with our new resource

Configuration SampleHashtable

{

    Import-DscResource -Module cBar

 

    Node (hostname)

    {

        cBar Sample

        {

            DisplayName   = 'NTDEV AD'

            Hashtable     = @{this='that'}

        }

    }

}

 

### Generate the MOF

SampleHashtable -OutputPath "$env:TEMP\SampleHashtable"

 

### Review the MOF

psedit "$env:TEMP\SampleHT\$(hostname).mof"

 

### Enact the config

Start-DscConfiguration -Path "$env:TEMP\SampleHashtable" -Verbose -Force -Wait

 

### Replace the DSC resource module code

Set-Content -Path 'C:\Program Files\WindowsPowerShell\Modules\cBar\DSCResources\cBar\cBar.psm1' -Value @'

function Get-TargetResource

{

      [CmdletBinding()]

      [OutputType([System.Collections.Hashtable])]

      param

      (

             [parameter(Mandatory = $true)]

             [System.String]

             $DisplayName

      )

}

 

function Set-TargetResource

{

      [CmdletBinding()]

      param

      (

             [parameter(Mandatory = $true)]

             [System.String]

             $DisplayName,

 

             [CimInstance]

             $Hashtable

      )

}

 

function Test-TargetResource

{

      [CmdletBinding()]

      [OutputType([System.Boolean])]

      param

      (

             [parameter(Mandatory = $true)]

             [System.String]

             $DisplayName,

 

             [CimInstance]

             $Hashtable

      )

    Write-Verbose "HT Properties: $($HT.CimInstanceProperties -join ',')"

    Write-Verbose "HT key:        $($HT.Key)"

    Write-Verbose "HT value:      $($HT.Value)"

    Write-Output $true

}

 

Export-ModuleMember -Function *-TargetResource

'@

 

<#

### My VM is on WMF 4 so I still need the heavy handed

### approach to getting the LCM to reload my DSC resource.

### find the Process that is hosting the DSC engine

$dscProcessID = Get-WmiObject msft_providers |

Where-Object {$_.provider -like 'dsccore'} |

Select-Object -ExpandProperty HostProcessIdentifier

### Kill it

Get-Process -Id $dscProcessID | Stop-Process -Force

#>

 

Here’s the LCM verbose output:

VERBOSE: Perform operation 'Invoke CimMethod' with following parameters, ''methodName' = SendConfigurationApply,'className' = MSFT_DSCLocalConfigu

rationManager,'namespaceName' = root/Microsoft/Windows/DesiredStateConfiguration'.

VERBOSE: An LCM method call arrived from computer IAMVM55763 with user sid S-1-5-21-32967844-2432541121-1187827502-500.

VERBOSE: [IAMVM55763]: LCM:  [ Start  Set      ]

VERBOSE: [IAMVM55763]: LCM:  [ Start  Resource ]  [[cBar]Sample]

VERBOSE: [IAMVM55763]: LCM:  [ Start  Test     ]  [[cBar]Sample]

VERBOSE: [IAMVM55763]:                            [[cBar]Sample] HT Properties:

VERBOSE: [IAMVM55763]:                            [[cBar]Sample] HT key:

VERBOSE: [IAMVM55763]:                            [[cBar]Sample] HT value:

VERBOSE: [IAMVM55763]: LCM:  [ End    Test     ]  [[cBar]Sample]  in 0.3590 seconds.

VERBOSE: [IAMVM55763]: LCM:  [ Skip   Set      ]  [[cBar]Sample]

VERBOSE: [IAMVM55763]: LCM:  [ End    Resource ]  [[cBar]Sample]

VERBOSE: [IAMVM55763]: LCM:  [ End    Set      ]    in  0.9177 seconds.

VERBOSE: Operation 'Invoke CimMethod' complete.

VERBOSE: Time taken for configuration job to complete is 1.256 seconds