# Getting information from SCCM Administration Service API

**SCCM** (now MECM) WMI contains a lot of valuable information about your environment, devices etc. In our company we have currently came across the situation, when we needed MAC addresses of computers managed by SCCM. The reason behind this was to give our users option to wake their remote computers by **WOL**, just by creating **JIRA ticket**.

We of course could've created admin account on SCCM server and utilize WMI to get such information, but there is nicer way and that is to use native SCCM REST API called [Administration Service](https://docs.microsoft.com/en-us/mem/configmgr/develop/adminservice/overview) :)

In this blog post I will show you, how to use this API to your advantage. 

---
**Table of Contents**
- [Prerequisites](#prerequisites)
- [Steps to make this work](#steps-to-make-this-work)
  - [1. Find out, where the information you need is stored](#1-find-out-where-the-information-you-need-is-stored)
    - [1.1 Case 1 - I know the exact WMI class, that contains information I need](#11-case-1---i-know-the-exact-wmi-class-that-contains-information-i-need)
    - [1.2 Case 2 - I don't know the WMI class, that contains information I need](#12-case-2---i-dont-know-the-wmi-class-that-contains-information-i-need)
      - [1.2.1 Check v1.0 source, if the information you are looking for, isn't there](#121-check-v10-source-if-the-information-you-are-looking-for-isnt-there)
  - [2. Create SCCM Security Role](#2-create-sccm-security-role)
  - [3. Add (service) account to created Security Role](#3-add-service-account-to-created-security-role)
  - [4. Request the data from Administration Service API](#4-request-the-data-from-administration-service-api)
- [Benefits over using WMI](#benefits-over-using-wmi)
- [Summary](#summary)

---

# Prerequisites
- SCCM with [installed Administration Service](https://docs.microsoft.com/en-us/mem/configmgr/develop/adminservice/set-up) role (SMS provider)
- Account that has at least READ rights on SCCM (or part of its data) or be SCCM admin to define security roles and assign it to some account
- Network access to SCCMs 443 port (https)

---

# Steps to make this work
## 1. Find out, where the information you need is stored
Administration Service offers two data sources. WMI and v1.0 (i.e. WMI migrated to new OData/SQL model). So there are two URLs for requests:
 - `https://<SCCMServerFQDN>/AdminService/wmi/`
 - `https://<SCCMServerFQDN>/AdminService/v1.0/`

### 1.1 Case 1 - I know the exact WMI class, that contains information I need
- In case you know, in what class are data you need stored, you can happily proceed to next section

### 1.2 Case 2 - I don't know the WMI class, that contains information I need
- Use Google
- Use [WMI Explorer](https://github.com/vinaypamnani/wmie2/releases) to connect to your SCCM server WMI `ROOT\SMS\site_<yourSCCMsiteCode>` and try to find the right class on your own
![image.webp](https://cdn.hashnode.com/res/hashnode/image/upload/v1620397244461/ycf73RRDt.webp)

#### 1.2.1 Check v1.0 source, if the information you are looking for, isn't there
- In browser running under user, that has admin rights for SCCM open `https://<SCCMServerFQDN>/AdminService/v1.0/` or check **List all available classes** section in Examples bellow

---

## 2. Create SCCM Security Role
> 
This step is necessary only if you don't want to use any of the [predefined Security Roles](https://docs.microsoft.com/en-us/mem/configmgr/core/understand/fundamentals-of-role-based-administration).

> 
For testing purposes, its ok to just use your SCCM admin account and omit this part

Security Roles allows you to delegate permissions to various part of SCCM. So you can create role, that will grant just read permissions over devices in some particular collection, read Bitlocker Recovery keys etc.

**Create Security Role for reading device information**
- just create new *Security Role* as shown bellow with just `READ` permission on `Collection` object
 - I have created `Device information READ` *Security Role*
![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1620885387001/QDQ9AgELUE.png)

**PS: Administration Service doesn't need any special privileges, it's just another option users have to access SCCM data (instead of console or WMI)**

---

## 3. Add (service) account to created Security Role
**Create Active Directory user and add him to the Security Role in SCCM**
- This account will be used for requesting information from API later
 - I have created `svc_WOL-CCM-READ` user domain account for this purpose, added it to `Device information READ` and limited its permissions just to one custom device collection

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1620885955456/-j36zES1S.png)

---

## 4. Request the data from Administration Service API
> 
In examples bellow, I use my [Invoke-CMAdminServiceQuery](https://github.com/ztrhgf/useful_powershell_functions/blob/master/SCCM/Invoke-CMAdminServiceQuery.ps1) PowerShell function. 
> 
The "make connection" part of the function is completely taken from https://github.com/CharlesNRU/mdm-adminservice/blob/master/Invoke-GetPackageIDFromAdminService.ps1 so kudos to that author. I've just generalized it and added the "query" part i.e. `source`, `select` and `filter` parameters. Plus features like TAB completion for classes in `source` parameter.

**IMPORTANT NOTES:**
- To import this [Invoke-CMAdminServiceQuery](https://github.com/ztrhgf/useful_powershell_functions/blob/master/SCCM/Invoke-CMAdminServiceQuery.ps1) function to your PS console, just download and dot source it
- `class` names used in function `source` parameter ARE CASE SENSITIVE!
- Run function under user with READ permissions to data you are trying to obtain! Or use `Credential` parameter to supply the right credentials**

So for my goal of getting device MAC address I had to run it like
```
$credential = Get-Credential -UserName MYDOMAIN\svc_WOL-CCM-READ -Message "Enter svc_WOL-CCM-READ password"

$MacAddrList = Invoke-CMAdminServiceQuery -Source "wmi/SMS_R_SYSTEM" -Filter "Name eq 'PC-01'" -Select MACAddresses -Credential $credential

# and result is
MACAddresses
------------
{00:15:5D:4A:70:F2, 00:15:5D:5B:35:A0, 00:15:5D:6D:19:AB, 00:15:5D:87:DF:7E, 00:15:5D:F4:06:1C, 7C:2A:31:2...

```

And thats it! Just filter out MAC Addresses of virtual NIC (starts with 00:15:5D) and you are good to go 👍

---

** Other examples:**

**1. List all available classes**
```
# get all available WMI classes
Invoke-CMAdminServiceQuery -Source "wmi/" -ServerFQDN SCCMServerFQDN

# FYI you can output the result to Out-GridView to get easy filtering option
Invoke-CMAdminServiceQuery -Source "wmi/" -ServerFQDN SCCMServerFQDN | Select Name | Out-GridView
```

**2. List all 'new OData/SQL' classes**
```
Invoke-CMAdminServiceQuery -Source "v1.0/" -ServerFQDN SCCMServerFQDN
```

**3. Get application deployments**
```
Invoke-CMAdminServiceQuery -Source "wmi/SMS_ApplicationAssignment" -ServerFQDN SCCMServerFQDN -Select ApplicationName,CollectionName 
```

**4. Get application installation status**
```
function Get-StatusType {
    param ([int] $statusType)

    switch ($statusType) {
        1 { "Success" }
        2 { "In Progress" }
        3 { "Requirements not met" }
        5 { "Error" }
        default {$statusType}
    }
}

function Get-EnforcementState {
    # https://docs.microsoft.com/en-us/mem/configmgr/develop/reference/sum/sms_updatecompliancestatus-server-wmi-class
    param ([int] $enforcementState)

    switch ($enforcementState) {
        1000        {"Success"}
        1001        {"Already compliant"}
        1002        {"Simulate Success"}
        2000        {"In progress"}
        2001        {"Waiting for content"}
        2002        {"Installing"}
        2003        {"Restart to continue"}
        2004        {"Waiting for maintenance window"}
        2005        {"Waiting for schedule"}
        2006        {"Downloading dependent content"}
        2007        {"Installing dependent content"}
        2008        {"Restart to complete"}
        2009        {"Content downloaded"}
        2010        {"Waiting for update"}
        2011        {"Waiting for user session reconnect"}
        2012        {"Waiting for user logoff"}
        2013        {"Waiting for user logon"}
        2014        {"Waiting to install"}
        2015        {"Waiting retry"}
        2016        {"Waiting For Presentation Mode"}
        2017        {"Waiting for orchestration"}
        2018        {"Waiting for network"}
        2019        {"Pending App-V Virtual Environment Update"}
        2020        {"Updating App-V Virtual Environment"}
        3000        {"Requirements not met"}
        3001        {"Host Platform Not Applicable"}
        4000        {"Unknown"}
        5000        {"Deployment failed"}
        5001        {"Evaluation failed"}
        5002        {"Deployment failed"}
        5003        {"Failed to locate content"}
        5004        {"Dependency installation failed"}
        5005        {"Failed to download dependent content"}
        5006        {"Conflicts with another application deployment"}
        5007        {"Waiting retry"}
        5008        {"Failed to uninstall superseded deployment type"}
        5009        {"Failed to download superseded deployment type"}
        5010        {"Failed to updating App-V Virtual Environment"}
        default { $enforcementState }
    }
}

# you can narrow down the selection to specific application using  -Filter "AppName eq 'SomeApp'"
Invoke-CMAdminServiceQuery -Source "wmi/SMS_AppDeploymentStatus" -Select AppName, StatusType, Total, CollectionName , EnforcementState | select AppName, @{n = 'Type'; e = { Get-StatusType $_.AppStatusType } }, @{n = 'EnforcementState'; e = { Get-EnforcementState $_.EnforcementState } }, CollectionName, Total
```

**5. Get SCCM scripts**
```
Invoke-CMAdminServiceQuery -Source "v1.0/Script" -ServerFQDN SCCMServerFQDN | Select ScriptName, ScriptContent
```
---

# Benefits over using WMI
- Admin rights not needed
- Security scoping options i. e. you can granularly limit what information particular account will be able to retrieve
- Firewall friendly (tcp 443)
- [Accessible through CMG](https://www.petervanderwoude.nl/post/enabling-the-configmgr-administration-service-through-the-cloud-management-gateway/)
- Its equally fast as getting information from WMI (both took approximately 300ms). You can test it yourselves via

```
Measure-Command { Invoke-CMAdminServiceQuery -Source "wmi/SMS_R_SYSTEM" -Filter "name eq 'PC-01'" -Select MACAddresses}

Measure-Command { Get-CimInstance -Class SMS_R_SYSTEM -Namespace "ROOT\SMS\site_$_SCCMSiteCode" -ComputerName $_SCCMServer -Property MacAddresses -Filter "name = 'PC-01'"}
```

---

# Summary
This built-in API is really great to to get information from SCCM, no matter if you need it for WOL as I did, or to get some information to your Task Sequence or PowerShell script. For more information, I recommend to [check this post](https://www.asquaredozen.com/2019/02/12/the-system-center-configuration-manager-adminservice-guide/)

If you have any questions, don't hesitate to give me some comment bellow!

