Monday, March 23, 2015

Metaverse Attribute Types

Discovery is addictively fun in PowerShell as you can really just keep using the Get-Member command to see what an object does, and Select-Object to see an object in action.

The sync engine has long lacked a DateTime type in the metaverse schema, requiring rules in deployments to convert to/from DataTimes.  DateTime conversions are frequent bug farms, so it would be pretty nice to just direct flow the values through the sync engine.

Anyhow, I was poking around with the new ADSync PowerShell module and took at look at the schema to see if the latest version of sync added any attribute types.

Here are the snippets:

### Get the members of the 'AttributeTypes' property

Get-ADSyncSchema | Select -ExpandProperty AttributeTypes | Get-Member

 

<#

   TypeName: Microsoft.IdentityManagement.PowerShell.ObjectModel.SchemaAttribute

 

Name                            MemberType Definition                                                                                                          

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

Equals                          Method     bool Equals(System.Object obj)                                                                                      

GetHashCode                     Method     int GetHashCode()                                                                                                   

GetSchema                       Method     System.Xml.Schema.XmlSchema GetSchema(), System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()                   

GetType                         Method     type GetType()                                                                                                      

ReadXml                         Method     void ReadXml(System.Xml.XmlReader reader), void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)               

ToString                        Method     string ToString()                                                                                                   

WriteXml                        Method     void WriteXml(System.Xml.XmlWriter writer), void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)             

AllowsMultipleValues            Property   bool AllowsMultipleValues {get;set;}                                                                                

Encrypted                       Property   bool Encrypted {get;set;}                                                                                           

Identifier                      Property   string Identifier {get;set;}                                                                                        

Indexable                       Property   bool Indexable {get;set;}                                                                                           

Indexed                         Property   bool Indexed {get;set;}                                                                                             

Name                            Property   string Name {get;set;}                                                                                              

SupportedAttributeOperationType Property   Microsoft.IdentityManagement.PowerShell.ObjectModel.AttributeOperationType SupportedAttributeOperationType {get;set;}

Type                            Property   Microsoft.IdentityManagement.PowerShell.ObjectModel.SchemaAttributeType Type {get;set;}                             

#>

 

 

### In the above output the 'Type' property is of type: Microsoft.IdentityManagement.PowerShell.ObjectModel.SchemaAttributeType

### We can easily check to see what the supported values are, like this:

[Microsoft.IdentityManagement.PowerShell.ObjectModel.SchemaAttributeType].GetEnumValues()

 

<#

String

Integer

Boolean

Binary

Reference

Number

#>

 

Wednesday, March 18, 2015

ErrorCode = 18 (There are no more files)

This is somewhat identity related, I promise.  Tried to use a VPN client lately with a virtual smart card; it had worked perfectly for a long time but now failed with “ErrorCode = 18 (There are no more files)”.  Thankful for the useful error message I began adding files to my computer but the problem persisted.

Coincidently I did create a new virtual smart card recently so wondered if the presence of two virtual smart cards was causing the problem.

There is good content on TechNet for virtual smart cards here: Virtual Smart Card Overview

That led me to TpmVscMgr.exe, a command-line tool for creating and deleting TPM virtual smart cards.  Pretty handy utility (TODO – find some nice APIs and write this thing as a PowerShell module).  The only trick to this utility is that it doesn’t list the virtual smart cards for you.

Listing the smart cards is kinda hacky but this worked for me:

### Get items from the registry

Get-ChildItem 'HKLM:\SYSTEM\CurrentControlSet\Control\DeviceClasses\{50dd5230-ba8a-11d1-bf5d-0000f805f530}' |

### Get just the DeviceInstance

Get-ItemProperty -Name DeviceInstance | Select DeviceInstance

Here is the output:

 

DeviceInstance                                                                                                                                                                                                    

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

ROOT\SMARTCARDREADER\0001                                                                                                                                                                                         

USB\VID_076B&PID_3021\5&3d7770d&0&1                                                                                                                                                                               

 

 

 

Those values work as input to TpmVscMgr.exe.  In my case I had one too many, and chose to delete one of them (an educated guess). 

After running the command I was able to VPN.  Yeah!

Thursday, March 12, 2015

Query AAD Using Graph API from PowerShell

One of my favourite things about PowerShell is discoverability, and how quickly you can use PowerShell to investigate and learn.  This post shows some snippets for using PowerShell to query the Azure Active Directory Graph API using PowerShell. 

NOTE: I’ve downloaded the Active Directory Authentication Library (ADAL) to C:\ADAL for the samples, so you’ll have to do something similar before the rest of the script will work.

Once authentication is done with ADAL, the PowerShell command ‘Invoke-RestMethod’ is used over and over by changing the URI slightly since the URI contains the query details.

<#

    Load the Active Directory Authentication Library

    Microsoft.IdentityModel.Clients.ActiveDirectory.dll

 

    https://www.nuget.org/packages/Microsoft.IdentityModel.Clients.ActiveDirectory

 

#>

Add-Type -Path 'C:\ADAL\Microsoft.IdentityModel.Clients.ActiveDirectory.dll'

 

<#

    Create the AuthenticationContext object

#>

$authenticationContext = New-Object Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext -ArgumentList @(

    'https://login.windows.net/common' #authority

    $false                             #validateAuthority

)

 

<#

    Create the AuthenticationResult object

 

    This overload is used: public AuthenticationResult AcquireToken(string resource, string clientId, Uri redirectUri)

 

    For more overloads, see:

    https://msdn.microsoft.com/en-us/library/microsoft.identitymodel.clients.activedirectory.authenticationcontext.acquiretoken.aspx

#>

$resource    = "https://graph.windows.net"

$clientId    = "1950a258-227b-4e31-a9cf-717495945fc2"

$redirectUri = [uri]"urn:ietf:wg:oauth:2.0:oob"

$authenticationResult = $authenticationContext.AcquireToken($resource, $clientId, $redirectUri)

 

<#

   Get all users

#>

Invoke-RestMethod -Method Get -Headers @{

    Authorization   = $authenticationResult.CreateAuthorizationHeader()

    'Content-Type'  = "application/json"

} -Uri ('https://graph.windows.net/{0}/users?api-version=2013-04-05' -f $authenticationResult.TenantId) |

select -expand Value

 

<#

   Get a user by UPN

#>

Invoke-RestMethod -Method Get -Headers @{

    Authorization   = $authenticationResult.CreateAuthorizationHeader()

    'Content-Type'  = "application/json"

} -Uri ('https://graph.windows.net/{0}/users/craig.martin@edgile.com?api-version=2013-04-05' -f $authenticationResult.TenantId)

 

<#

   Get a user by filter

#>

Invoke-RestMethod -Method Get -Headers @{

    Authorization   = $authenticationResult.CreateAuthorizationHeader()

    'Content-Type'  = "application/json"

} -Uri ('https://graph.windows.net/{0}/users?$filter=givenName eq ''Craig'' and surname eq ''martin''&api-version=2013-04-05' -f $authenticationResult.TenantId)

 

<#

   Get deltas

#>

Invoke-RestMethod -Method Get -Headers @{

    Authorization   = $authenticationResult.CreateAuthorizationHeader()

    'Content-Type'  = "application/json"

} -Uri ('https://graph.windows.net/{0}/directoryObjects?api-version=2013-04-05&deltaLink=' -f $authenticationResult.TenantId)

 

<#

   Get deltas with only the specified attributes

#>

Invoke-RestMethod -Method Get -Headers @{

    Authorization   = $authenticationResult.CreateAuthorizationHeader()

    'Content-Type'  = "application/json"

} -Uri ('https://graph.windows.net/{0}/directoryObjects?api-version=2013-04-05&deltaLink=&$select=User/displayName,User/givenName' -f $authenticationResult.TenantId)

 

 

Desired State Configuration–ConfigurationMode

Working on easing my way into running DSC on some FIM servers and want to tell the Local Configuration Manager (LCM) to test the objects but not set them.

DSC allows you to configure the LCM with a property named ‘ConfigurationMode’ which accepts values of:

  • ApplyOnly – Configuration is applied once
  • ApplyAndMonitor – Configuration is applied, and LCM monitors whether any changes occur.  If configuration drift is detected, it is reported in the logs.
  • ApplyAndAutoCorrect – Configuration is applied, and LCM monitors whether any changes occur.  If configuration drift is detected, LCM enforces the configuration.

ConfigurationMode is then useful for previewing what changes DSC wants to correct.

There is a slight gotcha here, in that ConfigurationMode is ignored by Start-DscConfiguration.  You might notice this if you push a configuration and watch it run successfully, then when it runs in the background thereafter it never corrects any objects.  I found this a little confusing.

Here’s a script snippet to observe the behaviour.  The configuration uses a Script resource (one of the built-in resources) to write messages (it doesn’t actually change anything).   It is a harmless way to see how the LCM behaves when ConfigurationMode is set to different values.

 

configuration DscTest

{

    node (hostname)

    {

        LocalConfigurationManager

        { 

             <#

             Specifies how often (in minutes) LCM ensures that the configuration is in the desired state.

             #>

             ConfigurationModeFrequencyMins = '60'

             <#

             Specifies how LCM should apply the configuration. Valid values are:

                · ApplyOnly:           Configuration is applied once.

                · ApplyAndMonitor:     Configuration is applied, and LCM monitors whether any changes occur. If configuration drift is detected, it is reported in logs.

                · ApplyAndAutoCorrect: Configuration is applied, and LCM monitors whether changes occur. If configuration drift is detected, LCM reapplies the configuration.

             #>

             ConfigurationMode = 'ApplyAndMonitor'

        }

 

        Script DscTestScript

        {

            GetScript  = {Write-Verbose "Got it."}

 

            TestScript = {Write-Verbose "Just Testing.";return $false}

 

            SetScript  = {Write-Warning "You won't see this if ConfigurationMode is ApplyAndMonitor."}

        }

    }

}

 

### Generate the MOF files

DscTest -OutputPath "$env:TEMP\DscTest" -Verbose

 

### Set the LCM settings

Set-DscLocalConfigurationManager -Path "$env:TEMP\DscTest" -Verbose

Get-DscLocalConfigurationManager

 

### Execute the configuration

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