Search This Blog

Jul 20, 2023

MS Graph RESTful Queries

  1.  Links
    1. Graph Explorer
    2. MS Odata Document
    3. Oasis Odata v4.0.1 URL Conventions, specifically, pay attention to 
      1. URL components
      2. Resource path and how to address entities, properties etc.
      3. Query Options
  2. An Odata URL is consist of 3 parts



    1. root URL: GET request made to root URL returns service document (that defines all resources available via the service)
    2. resource path: Entity or entity sets that are accessible via RESTful API
    3. Query option: select, filter, count, skip, order, top etc. See next section 
  3. Addressing
    1. Getting entity set:    GET serviceRoot/users
    2. Getting individual entity by key:    GET serviceRoot/users('john.doe@example.com')
    3. Getting entity property    GET serviceRoot/users/displayName
    4. Getting entity property raw value:    GET serviceRoot/users/displayName/$value
    5. Getting entity set:    GET serviceRoot/users
    6. Getting entity set:    GET serviceRoot/users
    7. Addressing metadata in powershell: $obj.'@odata.type'
      The key here is that the dot (.) between "odata" and "type" is not denotation of a sub-property, but just a normal text character as part of the property name '@odata.type' (so we quote the whole string)
  4. Query options
    1. Filter:
      1. Filter operators: eq/ne/gt/ge/lt/le/and/or/not/has/in
      2. Filter functions: contains/startsWith/endsWith/indexOf/concat/subString
      3. Collection functions: hasSubset/hasSubsequence
      4. More functions on Oasis URL above
      5. Example #1:    GET serviceRoot/users?$filter=upn eq 'johnDoe@example.com'
      6. Example #2, filter against complex type. This query finds airports whose address contains "San Francisco", where address is a property of a complex type Location:    GET serviceRoot/Airports?$filter=contains(Location/Address, 'San Francisco')
      7. Example #3:    GET serviceRoot/users?$filter=upn in {upn1@x.com,upn2@x.com}'
    2. Expand:
      1. Navigation properties: any property that can link to another entity. For example, "memberof", "manager" property of a user
      2. Example #1:    GET serviceRoot/users?$filter=upn eq 'johnDoe@example.com'$expand=manager
      3. Example #2:    $uObj=get-mgUser ... -expandproperty manager; $uObj.manager.additionalProperties.displayName
      4. Example #3:    get-mgUser ... -expandproperty "manager(`$select=displayName,jobTitle)"
    3. Select:
      1. Example #1:    GET serviceRoot/users?$select=*
    4. OrderBy:
      1. Example #1:    GET serviceRoot/users?$expand=manager($orderby=department)
      2. Example #2, order by the count of members:    GET serviceRoot/groups?$orderby=members/$count
    5. Top/Skip/Count
    6. any/all operator
      1. GET serviceRoot/People?$filter=Emails/any(s:endswith(s, 'contoso.com'))
  5. Literals
    1. null/$it/$root/$this
  6. placeholder

Jul 14, 2023

Enabling SMS Communication Using Azure Communication Service

Recently adding SMS alerting function to a monitoring program that my son wrote. Below are high level steps for North America developers.


  1. Assuming you already have App Service Plan and App Service in Azure
  2. Request SMS service
    1. Search "Communication Service" -> "create" to create a communication service instance
    2. Once created, under "Phone numbers", request a phone number. 
      1. Only toll free number can send SMS messages
      2. Cost (as of July 2023): $2/month + per message cost (neglectable)
      3. You can also request short code ID or aliphatic ID for extra cost
  3. Submit request for SMS sending
    1. In same page of the communication service instance, under "Regulatory Documents", submit a request. 
    2. "opt-in type" refers to how "customers" (as the regulatory is designed around marketing SMS messages) opt-in/opt-out. It could be SMS, web portal, paper form, etc. You have to provide evidence(screenshot) that there is such opt-in option available to customers
    3. It could take weeks to get approval
    4. Your outbound messages are blocked until your request is approved in Canada. In the States, you can send limited number of messages before approval
  4. Sample code to send SMS message

Jan 5, 2023

How AD decides Kerberos encryption type per user/computer basis

Supposed that there is no GPO to enforce supported ciphers, on a per principal basis, it is determined as below:


If msDS-SupportedEncryptedTypes is populated, then use values defined in this attribute. It's a 5-bit flag
      • bit 0   DES-CBC-CRC
      • bit 1   DES-CBC-MD5
      • bit 2   RC4-HMAC
      • bit 3   AES128-CTS-HMAC-SHA1-96
      • bit 4   AES256-CTS-HMAC-SHA1-96
If msDS-SupportedEncryptedTypes is NOT populated, then AD reads values in userAccoutControl

              • if 0x200000 is set, DES will be used
              • if 0x200000 is not set, default to RC4 for 2008/7 and later

          Default behavior:
          • Computer account: msDS-SupportedEncryptedTypes set. OS 2008/Win7 and newer: DES is disabled
          • User account: msDS-SupportedEncryptedTypes is not set so RC4 is used see here, unless userAccountControl forces DES
          • Referral Ticket/Trust object: higher of DES/RC4 that is mutually supported by client and authenticating domain. If both client and trust don't have any custom value set, cipher is RC4.

            NOTE/WARNING: If you enabled "AES" support on trust using GUI, only AES will be supported; RC4 will be disabled. If you want to add "AES" on top of RC4, use ksetup to change trust.
          PS. Above behavior is always for Service Ticket.
              Since TGT is meant for DCs to read, it always uses what DC supports, and is irrelevant to what is defined on individual accounts.

          Sample Script to find risky users

          #Bitwise AND: 1.2.840.113556.1.4.803
          #Bitwise OR : 1.2.840.113556.1.4.804
          # 2097152 is 0x200000, bit mask for userAccountControl DES enforced
          # 3 is 0b11, covers the last 2 bits of msDS-SupportedEncryptionTypes, which enables DES

          # list users who
              # user object, and
              # enabled, and
                  # supportedType set with DES, or
                  # supportedTYpe not set but userAccountControl DES set
                  
          $ldapfilter=@("(&",`
              "(objectclass=user)",`                                                         # user Object
              "(!(userAccountControl:1.2.840.113556.1.4.803:=2))",`                          # enabled
              "(|",` 
                  "(msDS-SupportedEncryptionTypes:1.2.840.113556.1.4.803:=3)",`              # DES defined in supportedType
                  "(&",`                                                                     # or DES not set in supported type but in userAccountControl
                      "(!(msDS-SupportedEncryptionTypes=*))",`                                   
                      "(userAccountControl:1.2.840.113556.1.4.803:=2097152)",`
                  ")",`
               ")",`
          ")")
          $ldapfilter = $ldapfilter -join ""
          $u=get-aduser -ldapfilter $ldapfilter -server foo.bar -Properties msDS-SupportedEncryptionTypes,enabled,userAccountControl,UseDESKeyOnly