Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joerodgers/b2e40e1eb028cede753234fc01e0b297 to your computer and use it in GitHub Desktop.
Save joerodgers/b2e40e1eb028cede753234fc01e0b297 to your computer and use it in GitHub Desktop.
function ConvertTo-Base64UrlEncodedString
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true)]
[byte[]]
$Bytes
)
$base64String = [System.Convert]::ToBase64String( $Bytes )
$base64String = $base64String -replace "=", ""
$base64String = $base64String -replace "\+", "-"
$base64String = $base64String -replace "\/", "_"
return $base64String
}
function New-ClientAssertion
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true)]
[System.Security.Cryptography.X509Certificates.X509Certificate2]
$Certificate,
[Parameter(Mandatory=$true)]
[Guid]
$TenantId,
[Parameter(Mandatory=$true)]
[Guid]
$ClientId,
[Parameter(Mandatory=$false)]
[DateTime]
$StartDate = [DateTime]::Today.AddDays(-1),
[Parameter(Mandatory=$false)]
[DateTime]
$EndDate = [DateTime]::Today.AddDays(1)
)
$hashAlgorithm = [System.Security.Cryptography.HashAlgorithmName]::SHA256
$rSASignaturePadding = [System.Security.Cryptography.RSASignaturePadding]::Pkcs1
$rsa = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey( $Certificate )
$header = @{
alg = "RS256"
typ = "JWT"
x5t = ConvertTo-Base64UrlEncodedString -Bytes $Certificate.GetCertHash()
}
$headerBytes = [System.Text.Encoding]::UTF8.GetBytes( ($header | ConvertTo-Json) )
$payload = @{
aud = "https://login.microsoftonline.com/$TenantId/oauth2/token"
iss = $ClientId.ToString()
sub = $ClientId.ToString()
jti = [Guid]::NewGuid().ToString()
nbf = [int](Get-Date -Date $StartDate.ToString() -UFormat %s)
exp = [int](Get-Date -Date $EndDate.ToString() -UFormat %s)
iat = [int](Get-Date -UFormat %s)
}
$payloadBytes = [System.Text.Encoding]::UTF8.GetBytes( ($payload | ConvertTo-Json) )
$unsignedJwt = (ConvertTo-Base64UrlEncodedString -Bytes $headerBytes) + "." + (ConvertTo-Base64UrlEncodedString -Bytes $payloadBytes)
$signedJwtBytes = $rsa.SignData( [System.Text.Encoding]::UTF8.GetBytes($unsignedJwt), $hashAlgorithm, $rSASignaturePadding )
$signedJwt = ConvertTo-Base64UrlEncodedString -Bytes $signedJwtBytes
return $unsignedJwt + "." + $signedJwt
}
function Rename-SpecicalChars
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$String
)
begin
{
}
process
{
$String = $String -replace "\+", "-"
$String = $String -replace "/", "_"
$String = $String -replace "=", ""
return $String
}
end
{
}
}
function ConvertTo-Base64EncodedString
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$String
)
begin
{
}
process
{
$bytes = [System.Text.Encoding]::UTF8.GetBytes($String)
return [System.Convert]::ToBase64String($bytes)
}
end
{
}
}
function Get-AccessToken
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true, ParameterSetName='Secret')]
[Parameter(Mandatory=$true, ParameterSetName='Certificate')]
[Parameter(Mandatory=$true, ParameterSetName='ClientAssertion')]
[string]
$ClientId,
[Parameter(Mandatory=$true, ParameterSetName='Secret')]
[string]
$ClientSecret,
[Parameter(Mandatory=$true, ParameterSetName='ClientAssertion')]
[string]
$ClientAssertion,
[Parameter(Mandatory=$true, ParameterSetName='Certificate')]
[System.Security.Cryptography.X509Certificates.X509Certificate2]
$Certificate,
[Parameter(Mandatory=$true, ParameterSetName='Secret')]
[Parameter(Mandatory=$true, ParameterSetName='Certificate')]
[Parameter(Mandatory=$true, ParameterSetName='ClientAssertion')]
[string]
$Tenant,
[Parameter(Mandatory=$true, ParameterSetName='Secret')]
[Parameter(Mandatory=$true, ParameterSetName='ClientAssertion')]
[Parameter(Mandatory=$true, ParameterSetName='Certificate')]
[string]
$Resource
)
begin
{
}
process
{
if( $PSCmdlet.ParameterSetName -eq "Secret" )
{
$body = @{
grant_type = "client_credentials"
client_id = $ClientId
client_secret = $ClientSecret
resource = $Resource
}
return Invoke-RestMethod -Uri "https://login.microsoftonline.com/$Tenant/oauth2/token" -Method Post -Body $body | SELECT -ExpandProperty access_token
}
elseif( $PSCmdlet.ParameterSetName -eq "ClientAssertion" )
{
$body = @{
scope = $Resource
client_id = $ClientId
client_assertion_type = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
client_assertion = $ClientAssertion
grant_type = "client_credentials"
}
return Invoke-RestMethod -Uri "https://login.microsoftonline.com/$Tenant/oauth2/v2.0/token" -Method Post -Body $body | SELECT -ExpandProperty access_token
}
else
{
$certficateBase64Hash = [System.Convert]::ToBase64String($Certificate.GetCertHash()) | Rename-SpecicalChars
$startDate = [DateTime]::Parse("1970-01-01T00:00:00Z").ToUniversalTime()
$jwtExpiration = New-TimeSpan -Start $startDate -End (Get-Date).ToUniversalTime().AddMinutes(2) | Select-Object -ExpandProperty TotalSeconds
$jwtExpiration = [System.Math]::Round($jwtExpiration,0)
$notBefore = New-TimeSpan -Start $startDate -End (Get-Date).ToUniversalTime() | Select-Object -ExpandProperty TotalSeconds
$notBefore = [System.Math]::Round($notBefore,0)
$jwtHeader = [PSCustomObject] @{
alg = "RS256"
typ = "JWT"
x5t = $certficateBase64Hash
} | ConvertTo-Json -Depth 100 | ConvertTo-Base64EncodedString
$jwtPayLoad = [PSCustomObject] @{
aud = "https://login.microsoftonline.com/$Tenant/oauth2/token"
exp = $jwtExpiration
iss = $ClientId
jti = [System.Guid]::NewGuid().ToString()
nbf = $notBefore
sub = $ClientId
} | ConvertTo-Json -Depth 100 | ConvertTo-Base64EncodedString
$jwt = "{0}.{1}" -f $jwtHeader, $jwtPayLoad
$bytes = $Certificate.PrivateKey.SignData( [System.Text.Encoding]::UTF8.GetBytes($jwt), [Security.Cryptography.HashAlgorithmName]::SHA256, [Security.Cryptography.RSASignaturePadding]::Pkcs1)
$signature = [System.Convert]::ToBase64String($bytes) | Rename-SpecicalChars
$jwt = "{0}.{1}" -f $jwt, $signature
$body = @{
grant_type = "client_credentials"
client_id = $ClientId
client_assertion = $jwt
client_assertion_type = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
scope = "$Resource/.default"
}
return Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/$Tenant/oauth2/v2.0/token" -Headers @{ "Authorization" = "Bearer $jwt" } -Body $body | Select-Object -ExpandProperty access_token
}
}
end
{
}
}
$certificate = Get-PfxCertificate -FilePath "C:\_temp\certificate.pfx"
$assertion = New-ClientAssertion `
-Certificate $certificate `
-TenantId $env:O365_TENANTID `
-ClientId $env:O365_CLIENTID `
-StartDate ([DateTime]::Today.AddDays(-1)) `
-EndDate ([DateTime]::Today.AddDays(365)) `
-ErrorAction Stop
$token = Get-AccessToken `
-ClientId $env:O365_CLIENTID `
-ClientAssertion $assertion `
-Tenant $env:O365_TENANTID `
-Resource "https://$env:O365_TENANT-admin.sharepoint.com/.default" `
-ErrorAction Stop
$response = Invoke-RestMethod `
-Method Get `
-Uri "https://$env:O365_TENANT-admin.sharepoint.com/_api/StorageQuotas()?api-version=1.3.2" `
-Headers @{ Authorization = "Bearer $token"; accept="application/json" } `
-ErrorAction Stop
$response.value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment