Initial Version
This commit is contained in:
commit
740994ae40
4 changed files with 217 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
*.html
|
132
AppleBusinessManager.psd1
Normal file
132
AppleBusinessManager.psd1
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
#
|
||||||
|
# Module manifest for module 'ABMPS'
|
||||||
|
#
|
||||||
|
# Generated by: Liam Steckler
|
||||||
|
#
|
||||||
|
# Generated on: 6/11/2025
|
||||||
|
#
|
||||||
|
|
||||||
|
@{
|
||||||
|
|
||||||
|
# Script module or binary module file associated with this manifest.
|
||||||
|
RootModule = 'AppleBusinessManager.psm1'
|
||||||
|
|
||||||
|
# Version number of this module.
|
||||||
|
ModuleVersion = '1.0'
|
||||||
|
|
||||||
|
# Supported PSEditions
|
||||||
|
# CompatiblePSEditions = @()
|
||||||
|
|
||||||
|
# ID used to uniquely identify this module
|
||||||
|
GUID = 'ba7191aa-8343-45d4-941b-52ddc74d7cc7'
|
||||||
|
|
||||||
|
# Author of this module
|
||||||
|
Author = 'Liam Steckler'
|
||||||
|
|
||||||
|
# Company or vendor of this module
|
||||||
|
CompanyName = 'Unknown'
|
||||||
|
|
||||||
|
# Copyright statement for this module
|
||||||
|
Copyright = '(c) Liam Steckler. All rights reserved.'
|
||||||
|
|
||||||
|
# Description of the functionality provided by this module
|
||||||
|
# Description = ''
|
||||||
|
|
||||||
|
# Minimum version of the PowerShell engine required by this module
|
||||||
|
PowerShellVersion = '7.0.0'
|
||||||
|
|
||||||
|
# Name of the PowerShell host required by this module
|
||||||
|
# PowerShellHostName = ''
|
||||||
|
|
||||||
|
# Minimum version of the PowerShell host required by this module
|
||||||
|
# PowerShellHostVersion = ''
|
||||||
|
|
||||||
|
# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
|
||||||
|
# DotNetFrameworkVersion = ''
|
||||||
|
|
||||||
|
# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
|
||||||
|
# ClrVersion = ''
|
||||||
|
|
||||||
|
# Processor architecture (None, X86, Amd64) required by this module
|
||||||
|
# ProcessorArchitecture = ''
|
||||||
|
|
||||||
|
# Modules that must be imported into the global environment prior to importing this module
|
||||||
|
# RequiredModules = @()
|
||||||
|
|
||||||
|
# Assemblies that must be loaded prior to importing this module
|
||||||
|
# RequiredAssemblies = @()
|
||||||
|
|
||||||
|
# Script files (.ps1) that are run in the caller's environment prior to importing this module.
|
||||||
|
# ScriptsToProcess = @()
|
||||||
|
|
||||||
|
# Type files (.ps1xml) to be loaded when importing this module
|
||||||
|
# TypesToProcess = @()
|
||||||
|
|
||||||
|
# Format files (.ps1xml) to be loaded when importing this module
|
||||||
|
# FormatsToProcess = @()
|
||||||
|
|
||||||
|
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
|
||||||
|
# NestedModules = @()
|
||||||
|
|
||||||
|
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
|
||||||
|
FunctionsToExport = '*'
|
||||||
|
|
||||||
|
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
|
||||||
|
CmdletsToExport = '*'
|
||||||
|
|
||||||
|
# Variables to export from this module
|
||||||
|
VariablesToExport = '*'
|
||||||
|
|
||||||
|
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
|
||||||
|
AliasesToExport = '*'
|
||||||
|
|
||||||
|
# DSC resources to export from this module
|
||||||
|
# DscResourcesToExport = @()
|
||||||
|
|
||||||
|
# List of all modules packaged with this module
|
||||||
|
# ModuleList = @()
|
||||||
|
|
||||||
|
# List of all files packaged with this module
|
||||||
|
# FileList = @()
|
||||||
|
|
||||||
|
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
|
||||||
|
PrivateData = @{
|
||||||
|
|
||||||
|
PSData = @{
|
||||||
|
|
||||||
|
# Tags applied to this module. These help with module discovery in online galleries.
|
||||||
|
# Tags = @()
|
||||||
|
|
||||||
|
# A URL to the license for this module.
|
||||||
|
# LicenseUri = ''
|
||||||
|
|
||||||
|
# A URL to the main website for this project.
|
||||||
|
# ProjectUri = ''
|
||||||
|
|
||||||
|
# A URL to an icon representing this module.
|
||||||
|
# IconUri = ''
|
||||||
|
|
||||||
|
# ReleaseNotes of this module
|
||||||
|
# ReleaseNotes = ''
|
||||||
|
|
||||||
|
# Prerelease string of this module
|
||||||
|
# Prerelease = ''
|
||||||
|
|
||||||
|
# Flag to indicate whether the module requires explicit user acceptance for install/update/save
|
||||||
|
# RequireLicenseAcceptance = $false
|
||||||
|
|
||||||
|
# External dependent modules of this module
|
||||||
|
# ExternalModuleDependencies = @()
|
||||||
|
|
||||||
|
} # End of PSData hashtable
|
||||||
|
|
||||||
|
} # End of PrivateData hashtable
|
||||||
|
|
||||||
|
# HelpInfo URI of this module
|
||||||
|
# HelpInfoURI = ''
|
||||||
|
|
||||||
|
# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
|
||||||
|
# DefaultCommandPrefix = ''
|
||||||
|
|
||||||
|
}
|
||||||
|
|
81
AppleBusinessManager.psm1
Normal file
81
AppleBusinessManager.psm1
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
#Requires -Version 7.0
|
||||||
|
#Requires -Module jwtPS
|
||||||
|
function Connect-AppleBusinessManager {
|
||||||
|
if (-not $Env:AppleBusinessManagerClientId -or -not $Env:AppleBusinessManagerPrivateKeyId -or -not $Env:AppleBusinessManagerPrivateKey) {
|
||||||
|
throw "Client ID, Private Key ID and Private Key environment variables were not set for Apple Business Manager"
|
||||||
|
}
|
||||||
|
$Script:ClientId = $Env:AppleBusinessManagerClientId
|
||||||
|
$Script:PrivateKey = $Env:AppleBusinessManagerPrivateKey
|
||||||
|
$Script:PrivateKeyId = $Env:AppleBusinessManagerPrivateKeyId
|
||||||
|
|
||||||
|
$Header = @{
|
||||||
|
'kid' = $Script:PrivateKeyId
|
||||||
|
}
|
||||||
|
|
||||||
|
$Payload = @{
|
||||||
|
aud = "https://account.apple.com/auth/oauth2/v2/token"
|
||||||
|
iss = $Script:ClientId
|
||||||
|
sub = $Script:ClientId
|
||||||
|
iat = ([System.DateTimeOffset]::Now).ToUnixTimeSeconds()
|
||||||
|
exp = ([System.DateTimeOffset]::Now.AddMinutes(15)).ToUnixTimeSeconds()
|
||||||
|
jti = [guid]::NewGuid()
|
||||||
|
}
|
||||||
|
|
||||||
|
$Hashing = [jwtTypes+encryption]::SHA256
|
||||||
|
$Signature = [jwtTypes+algorithm]::ECDsa
|
||||||
|
$Algorithm = [jwtTypes+cryptographyType]::new($Signature, $Hashing)
|
||||||
|
$JWT = New-JWT -Payload $Payload -Algorithm $Algorithm -Secret $Script:PrivateKey -Header $Header
|
||||||
|
Write-Verbose $JWT
|
||||||
|
|
||||||
|
$Script:Body = @{
|
||||||
|
'grant_type' = 'client_credentials'
|
||||||
|
'client_id' = $Script:ClientId
|
||||||
|
'client_assertion' = $JWT
|
||||||
|
'client_assertion_type' = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
|
||||||
|
'scope' = 'business.api'
|
||||||
|
}
|
||||||
|
|
||||||
|
$Script:AuthResponse = Invoke-RestMethod -Method Post -Uri 'https://account.apple.com/auth/oauth2/token' -Body $Script:Body -SkipHttpErrorCheck
|
||||||
|
if ($Script:AuthResponse.error) {
|
||||||
|
throw $Script:AuthResponse.Error
|
||||||
|
}
|
||||||
|
$Script:ExpiresAt = (Get-Date).AddSeconds($Script:AuthResponse.expires_in)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-AppleBusinessManagerBearerToken {
|
||||||
|
if (-not $Script:AuthResponse) {
|
||||||
|
try {
|
||||||
|
Connect-AppleBusinessManager
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
throw "Authorization has not been completed, use Connect-AppleBusinessManager first."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((Get-Date).AddMinutes(1) -ge $Script:ExpiresAt) {
|
||||||
|
# Access token is approaching expiration, get a new access token
|
||||||
|
Connect-AppleBusinessManager
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($Script:AuthResponse.access_token | ConvertTo-SecureString -AsPlainText -Force)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-AppleBusinessManagerPagedApiRequest {
|
||||||
|
param (
|
||||||
|
[Parameter(Mandatory = $true)][uri] $Uri
|
||||||
|
)
|
||||||
|
$Results = New-Object System.Collections.ArrayList
|
||||||
|
while ($Uri) {
|
||||||
|
$Result = Invoke-RestMethod $Uri -Authentication Bearer -Token (Get-AppleBusinessManagerBearerToken) -ErrorAction Stop
|
||||||
|
$Uri = $Result.links.next
|
||||||
|
$Results.AddRange($Result.data) | Out-Null
|
||||||
|
}
|
||||||
|
return $Results
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-AppleBusinessManagerOrgDevices {
|
||||||
|
return Invoke-AppleBusinessManagerPagedApiRequest -Uri "https://api-business.apple.com/v1/orgDevices"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-AppleBusinessManagerMdmServers {
|
||||||
|
return Invoke-AppleBusinessManagerPagedApiRequest -Uri "https://api-business.apple.com/v1/mdmServers"
|
||||||
|
}
|
3
README.md
Normal file
3
README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Apple Business Manager API Module for PowerShell
|
||||||
|
To use this module, you'll need to convert the private key from Apple to a .NET friendly format:
|
||||||
|
```openssl pkcs8 -topk8 -inform PEM -outform PEM -in [path to your key from Apple] -out [path to where you want to save the converted key] -nocrypt```
|
Loading…
Add table
Add a link
Reference in a new issue