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

 

Wednesday, April 15, 2015

Using PowerShell with AAD Sync Connector Partitions

It is so cool to have a PowerShell module for the sync engine in AAD, albeit sometimes a bit frustrating.  This post shows some of the functionality that works, as well as some of it that isn’t working just yet.

To cut to the chase, I am able to read partitions but only with the Get-ADSyncConnector command (the Get-ADSyncConnectorPartition command doesn’t work) but so far I have not figured out how to use the PowerShell module to update partitions (the Update-ADSyncConnectorPartition command doesn’t seem to work).

In the snippets below I try the same test twice sometimes, once for an AD connector, then again for an AAD connector.  The new PowerModule seems to work better for connectors based on ECMA 2, such as the AAD Connector.  The AD connector is legacy (man I feel old as I type that) so sometimes the commands in the ADSync PowerShell module do not work.

 

### What commands are available for Paritions?

Get-Command -Module ADSync -Name *partition*

<#

CommandType     Name                                               ModuleName                                                                                                                                             

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

Cmdlet          Disable-ADSyncConnectorPartition                   ADSync                                                                                                                                                 

Cmdlet          Disable-ADSyncConnectorPartitionHierarchy          ADSync                                                                                                                                                 

Cmdlet          Enable-ADSyncConnectorPartition                    ADSync                                                                                                                                                 

Cmdlet          Enable-ADSyncConnectorPartitionHierarchy           ADSync                                                                                                                                                 

Cmdlet          Get-ADSyncConnectorPartition                       ADSync                                                                                                                                                 

Cmdlet          Get-ADSyncConnectorPartitionHierarchy              ADSync                                                                                                                                                 

Cmdlet          Update-ADSyncConnectorPartition                    ADSync

#>

 

### TEST - Get a partition by name for an AD connector (NOT based on ECMA 2)

### FAIL - returns nothing

Get-ADSyncConnectorPartition -Name litware.ca -Connector (Get-ADSyncConnector -Name litware.ca)

 

### TEST - Get a partition by name for an AAD connector (based on ECMA 2)

### FAIL - returns nothing

Get-ADSyncConnectorPartition -Connector (Get-ADSyncConnector -Name 'litware.ca - AAD') -Name Default

 

### TEST - Get all paritions

### FAIL - returns the wrong object (Connector instead of ConnectorPartition)

Get-ADSyncConnectorPartition -Connector (Get-ADSyncConnector -Name litware.ca)

Get-ADSyncConnectorPartition -Connector (Get-ADSyncConnector -Name 'litware.ca - AAD')

<#

ConnectorTypeName             : AD

Identifier                    : 929d2c70-42bf-4ad5-b02e-7b47f7003edd

Version                       : 1

InternalVersion               : 0

FormatVersion                 : 1

Name                          : litware.ca

Type                          : AD

Description                   :

CreationTime                  : 2/24/2015 12:16:37 AM

LastModificationTime          : 2/24/2015 12:16:37 AM

Partitions                    : {default}

RunProfiles                   : {Delta Import, Delta Synchronization, Export, Full Import...}

ComponentProvisioningMappings : {}

PasswordManagementSettings    : Microsoft.IdentityManagement.PowerShell.ObjectModel.ConnectorPasswordManagementSettings

Schema                        : Microsoft.IdentityManagement.PowerShell.ObjectModel.Schema

ConnectivityParameters        : {forest-port, forest-guid, default-ssl-strength, password...}

GlobalParameters              : {ADS_UF_ACCOUNTDISABLE, ADS_GROUP_TYPE_GLOBAL_GROUP, ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP, ADS_GROUP_TYPE_LOCAL_GROUP...}

CapabilityParameters          : {}

SchemaParameters              : {}

ObjectInclusionList           : {user, inetOrgPerson, group, contact...}

AttributeInclusionList        : {mailNickname, isCriticalSystemObject, sAMAccountName, msExchRecipientTypeDetails...}

AnchorConstructionSettings    : {}

ListName                      :

CompanyName                   :

SubType                       :

ExtensionConfiguration        : Microsoft.IdentityManagement.PowerShell.ObjectModel.ConnectorExtensionConfiguration

PasswordHashConfiguration     :

AADPasswordResetConfiguration :

allParameterDefinitions       : {}

#>

 

 

### TEST - (workaround) Get the Partitions through the 'Partitions' property on the connector object

### PASS

Get-ADSyncConnector -Name 'litware.ca - AAD' | Select -ExpandProperty Partitions

<#

Identifier              : f083884f-dbf1-4eef-a5b3-02adabc96dbd

DN                      : default

Version                 : 1

CreationTime            : 2/24/2015 12:16:38 AM

LastModificationTime    : 2/24/2015 12:16:38 AM

Selected                : True

ConnectorPartitionScope : Microsoft.IdentityManagement.PowerShell.ObjectModel.ConnectorPartitionScope

Name                    : default

Parameters              : {}

IsDomain                : True

ECMAWaterMark           : ....

#>

 

 

### TEST - (workaround) Get just one Partition

### PASS

Get-ADSyncConnector -Name litware.ca | Select -ExpandProperty Partitions | Where Name -eq litware.ca

 

### TEST - Update a partition using Update-ADSyncConnectorPartition

### FAIL - no error, just doesn't apply the change to the server

$connector = Get-ADSyncConnector -Name litware.ca

$connector | Select -ExpandProperty Partitions | Where Name -eq squamish.litware.ca | ForEach-Object {$_.Selected = $false}

Update-ADSyncConnectorPartition -Connector $connector -Verbose

Get-ADSyncConnector -Name litware.ca | Select -ExpandProperty Partitions | Where Name -eq squamish.litware.ca