Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions verkadaModule/Public/Add-VerkadaAccessUserMfaCode.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
function Add-VerkadaAccessUserMfaCode{
<#
.SYNOPSIS
Adds a mfa code credential to a user using https://apidocs.verkada.com/reference/postmfacodeviewv1

.DESCRIPTION
Adds a mfa code credential to a user given a specified user_id or external_id and org_id. MFA code object will be passed in the body of the request as a json.
The org_id and reqired token can be directly submitted as parameters, but is much easier to use Connect-Verkada to cache this information ahead of time and for subsequent commands.

.LINK
https://github.com/bepsoccer/verkadaModule/blob/master/docs/function-documentation/Add-VerkadaAccessMfaCode.md

.EXAMPLE
Add-VerkadaAccessUserMfaCode -mfaCode '9567' -userId '801c9551-b04c-4293-84ad-b0a6aa0588b3'
This adds the MFA code 9567 to the Access user's profile with userId 801c9551-b04c-4293-84ad-b0a6aa0588b3. The org_id and token will be populated from the cached created by Connect-Verkada.

.EXAMPLE
Add-VerkadaAccessUserMfaCode -mfaCode '9567' -externalId 'newUserUPN@contoso.com' -org_id '7cd47706-f51b-4419-8675-3b9f0ce7c12d' -x_verkada_auth_api 'sd78ds-uuid-of-verkada-token'
This adds the MFA code 9567 to the Access user's profile with externalId newUserUPN@contoso.com. The org_id and token are submitted as parameters in the call.
#>
[CmdletBinding(PositionalBinding = $true)]
[Alias("Add-VrkdaAcUsrMfaCd","a-VrkdaAcUsrMfaCd")]
param (
#The UUID of the user
[Parameter(ValueFromPipelineByPropertyName = $true)]
[ValidateNotNullOrEmpty()]
[ValidatePattern('^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$')]
[Alias('user_id')]
[String]$userId,
#unique identifier managed externally provided by the consumer
[Parameter(ValueFromPipelineByPropertyName = $true)]
[Alias('external_id')]
[String]$externalId,
#The Access MFA code
[Parameter(ValueFromPipelineByPropertyName = $true)]
[ValidatePattern('^\d{4,16}$')]
[Alias('mfa_code','code')]
[string]$mfaCode,
#The UUID of the organization the user belongs to
[Parameter(ValueFromPipelineByPropertyName = $true)]
[ValidateNotNullOrEmpty()]
[ValidatePattern('^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$')]
[String]$org_id = $Global:verkadaConnection.org_id,
#The public API token obatined via the Login endpoint to be used for calls that hit the public API gateway
[Parameter()]
[ValidateNotNullOrEmpty()]
[String]$x_verkada_auth_api = $Global:verkadaConnection.x_verkada_auth_api,
#The region of the public API to be used
[Parameter()]
[ValidateSet('api','api.eu','api.au')]
[String]$region='api',
#Switch to write errors to file
[Parameter()]
[switch]$errorsToFile
)

begin {
$url = "https://$($region).verkada.com/access/v1/credentials/mfa_code"
#parameter validation
if ([string]::IsNullOrEmpty($org_id)) {throw "org_id is missing but is required!"}
if ([string]::IsNullOrEmpty($x_verkada_auth_api)) {throw "x_verkada_auth_api is missing but is required!"}
$myErrors = @()
} #end begin

process {
if ([string]::IsNullOrEmpty($mfaCode)) {
Write-Error "mfaCode is missing but is required!"
return
}

$body_params = @{
'code' = $mfaCode
}

$query_params = @{}
if (!([string]::IsNullOrEmpty($externlId))){
$query_params.externl_id = $externlId
} elseif (!([string]::IsNullOrEmpty($userId))){
$query_params.user_id = $userId
} else {
Write-Error "Either externalId or userId required"
return
}

try {
$response = Invoke-VerkadaRestMethod $url $org_id $x_verkada_auth_api $query_params -body_params $body_params -method POST
return $response
}
catch [Microsoft.PowerShell.Commands.HttpResponseException] {
$err = $_.ErrorDetails | ConvertFrom-Json
$errorMes = $_ | Convertto-Json -WarningAction SilentlyContinue
$err | Add-Member -NotePropertyName StatusCode -NotePropertyValue (($errorMes | ConvertFrom-Json -Depth 100 -WarningAction SilentlyContinue).Exception.Response.StatusCode) -Force
$msg = "$($err.StatusCode) - $($err.message)"
$msg += ": $(($query_params + $body_params) | ConvertTo-Json -Compress)"
Write-Error $msg
$myErrors += $msg
$msg = $null
}
catch [VerkadaRestMethodException] {
$msg = $_.ToString()
$msg += ": $(($query_params + $body_params) | ConvertTo-Json -Compress)"
Write-Error $msg
$myErrors += $msg
$msg = $null
}
} #end process

end {
if ($errorsToFile.IsPresent){
if (![string]::IsNullOrEmpty($myErrors)){
Get-Date | Out-File ./errors.txt -Append
$myErrors | Out-File ./errors.txt -Append
}
}
} #end end
} #end function
9 changes: 0 additions & 9 deletions verkadaModule/Public/Connect-Verkada.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,6 @@ function Connect-Verkada
$x_verkada_auth_api = Invoke-RestMethod -Uri "https://$($region).verkada.com/token" -Method 'POST' -Headers $login_headers -StatusCodeVariable responseCode | Select-Object -ExpandProperty token
$Global:verkadaConnection.x_verkada_auth_api = $x_verkada_auth_api

$body = @{
'org_id' = $Global:verkadaConnection.org_id
'page_size' = "1"
}
$headers=@{
'x-verkada-auth' = $Global:verkadaConnection.x_verkada_auth_api
}

#$response = Invoke-RestMethod -Uri "https://$($region).verkada.com/core/v1/audit_log" -Body $body -Headers $headers -StatusCodeVariable responseCode
if (!($noOutput)){Write-Host -ForegroundColor green "$responseCode - Successfully connected to Verkada Command with API Token"}
return
} catch [Microsoft.PowerShell.Commands.HttpResponseException] {
Expand Down
116 changes: 116 additions & 0 deletions verkadaModule/Public/Remove-VerkadaAccessUserMfaCode.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
function Remove-VerkadaAccessUserMfaCode{
<#
.SYNOPSIS
Deletes a mfa code credential from a specified user using https://apidocs.verkada.com/reference/deletemfacodeviewv1

.DESCRIPTION
Deletes a mfa code credential from a specified user by providing the user_id or the external_id, the org_id, and the mfa_code.
The org_id and reqired token can be directly submitted as parameters, but is much easier to use Connect-Verkada to cache this information ahead of time and for subsequent commands.

.LINK
https://github.com/bepsoccer/verkadaModule/blob/master/docs/function-documentation/Remove-VerkadaAccessMfaCode.md

.EXAMPLE
Remove-VerkadaAccessUserMfaCode -mfaCode '9567' -userId '801c9551-b04c-4293-84ad-b0a6aa0588b3'
This deletes the MFA code 9567 from the Access user's profile with userId 801c9551-b04c-4293-84ad-b0a6aa0588b3. The org_id and token will be populated from the cached created by Connect-Verkada.

.EXAMPLE
Remove-VerkadaAccessUserMfaCode -mfaCode '9567' -externalId 'newUserUPN@contoso.com' -org_id '7cd47706-f51b-4419-8675-3b9f0ce7c12d' -x_verkada_auth_api 'sd78ds-uuid-of-verkada-token'
This deletes the MFA code 9567 from the Access user's profile with externalId newUserUPN@contoso.com. The org_id and token are submitted as parameters in the call.
#>
[CmdletBinding(PositionalBinding = $true)]
[Alias("Remove-VrkdaAcUsrMfaCd","rm-VrkdaAcUsrMfaCd")]
param (
#The UUID of the user
[Parameter(ValueFromPipelineByPropertyName = $true)]
[ValidateNotNullOrEmpty()]
[ValidatePattern('^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$')]
[Alias('user_id')]
[String]$userId,
#unique identifier managed externally provided by the consumer
[Parameter(ValueFromPipelineByPropertyName = $true)]
[Alias('external_id')]
[String]$externalId,
#The Access MFA code
[Parameter(ValueFromPipelineByPropertyName = $true)]
[ValidatePattern('^\d{4,16}$')]
[Alias('mfa_code')]
[string]$mfaCode,
#The UUID of the organization the user belongs to
[Parameter(ValueFromPipelineByPropertyName = $true)]
[ValidateNotNullOrEmpty()]
[ValidatePattern('^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$')]
[String]$org_id = $Global:verkadaConnection.org_id,
#The public API token obatined via the Login endpoint to be used for calls that hit the public API gateway
[Parameter()]
[ValidateNotNullOrEmpty()]
[String]$x_verkada_auth_api = $Global:verkadaConnection.x_verkada_auth_api,
#The region of the public API to be used
[Parameter()]
[ValidateSet('api','api.eu','api.au')]
[String]$region='api',
#Switch to write errors to file
[Parameter()]
[switch]$errorsToFile
)

begin {
$url = "https://$($region).verkada.com/access/v1/credentials/mfa_code"
#parameter validation
if ([string]::IsNullOrEmpty($org_id)) {throw "org_id is missing but is required!"}
if ([string]::IsNullOrEmpty($x_verkada_auth_api)) {throw "x_verkada_auth_api is missing but is required!"}
$myErrors = @()
} #end begin

process {
if ([string]::IsNullOrEmpty($mfaCode)) {
Write-Error "mfaCode is missing but is required!"
return
}

$body_params = @{}

$query_params = @{
'code' = $mfaCode
}
if (!([string]::IsNullOrEmpty($externlId))){
$query_params.externl_id = $externlId
} elseif (!([string]::IsNullOrEmpty($userId))){
$query_params.user_id = $userId
} else {
Write-Error "Either externalId or userId required"
return
}

try {
Invoke-VerkadaRestMethod $url $org_id $x_verkada_auth_api $query_params -body_params $body_params -method Delete
return "Code $mfaCode successfully deleted"
}
catch [Microsoft.PowerShell.Commands.HttpResponseException] {
$err = $_.ErrorDetails | ConvertFrom-Json
$errorMes = $_ | Convertto-Json -WarningAction SilentlyContinue
$err | Add-Member -NotePropertyName StatusCode -NotePropertyValue (($errorMes | ConvertFrom-Json -Depth 100 -WarningAction SilentlyContinue).Exception.Response.StatusCode) -Force
$msg = "$($err.StatusCode) - $($err.message)"
$msg += ": $(($query_params + $body_params) | ConvertTo-Json -Compress)"
Write-Error $msg
$myErrors += $msg
$msg = $null
}
catch [VerkadaRestMethodException] {
$msg = $_.ToString()
$msg += ": $(($query_params + $body_params) | ConvertTo-Json -Compress)"
Write-Error $msg
$myErrors += $msg
$msg = $null
}
} #end process

end {
if ($errorsToFile.IsPresent){
if (![string]::IsNullOrEmpty($myErrors)){
Get-Date | Out-File ./errors.txt -Append
$myErrors | Out-File ./errors.txt -Append
}
}
} #end end
} #end function
56 changes: 30 additions & 26 deletions verkadaModule/verkadaModule.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#
# Generated by: Verkada SE Community
#
# Generated on: 10/23/2025
# Generated on: 10/22/2025
#

@{
Expand Down Expand Up @@ -71,10 +71,11 @@ PowerShellVersion = '6.1'
# 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 = 'Add-VerkadaAccessGroup', 'Add-VerkadaAccessSiteAdmin',
'Add-VerkadaAccessUserCard', 'Add-VerkadaAccessUserLicensePlate',
'Add-VerkadaCamera', 'Add-VerkadaCommandSite',
'Add-VerkadaCommandUser', 'Add-VerkadaHelixEvent',
'Add-VerkadaLicensePlateOfInterest', 'Add-VerkadaWorkplaceEmployee',
'Connect-Verkada', 'Disable-VerkadaAccessUserCard',
'Add-VerkadaAccessUserMfaCode', 'Add-VerkadaCamera',
'Add-VerkadaCommandSite', 'Add-VerkadaCommandUser',
'Add-VerkadaHelixEvent', 'Add-VerkadaLicensePlateOfInterest',
'Add-VerkadaWorkplaceEmployee', 'Connect-Verkada',
'Disable-VerkadaAccessUserCard',
'Disable-VerkadaAccessUserLicensePlate', 'Disconnect-Verkada',
'Enable-VerkadaAccessUserCard',
'Enable-VerkadaAccessUserLicensePlate', 'Find-VerkadaCommandUser',
Expand All @@ -99,6 +100,7 @@ FunctionsToExport = 'Add-VerkadaAccessGroup', 'Add-VerkadaAccessSiteAdmin',
'Remove-VerkadaAccessUserCard', 'Remove-VerkadaAccessUserEntryCode',
'Remove-VerkadaAccessUserFromGroup',
'Remove-VerkadaAccessUserLicensePlate',
'Remove-VerkadaAccessUserMfaCode',
'Remove-VerkadaAccessUserProfilePicture',
'Remove-VerkadaAccessUserRemoteUnlock',
'Remove-VerkadaCameraArchive', 'Remove-VerkadaCommandUser',
Expand Down Expand Up @@ -130,7 +132,8 @@ CmdletsToExport = @()
# 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 = 'a-VrkdaAcGrp', 'Add-VrkdaAcGrp', 'a-VrkdaAcUsrCrd',
'Add-VrkdaAcUsrCrd', 'a-VrkdaAcUsrLPR', 'Add-VrkdaAcUsrLPR',
'a-VrkdaCmdUsr', 'Add-VrkdaCmdUsr', 'a-VrkdaHlxEvt', 'Add-VrkdaHlxEvt',
'a-VrkdaAcUsrMfaCd', 'Add-VrkdaAcUsrMfaCd', 'a-VrkdaCmdUsr',
'Add-VrkdaCmdUsr', 'a-VrkdaHlxEvt', 'Add-VrkdaHlxEvt',
'Add-VerkadaLPoI', 'a-VrkdaWrkEmp', 'Add-VrkdaWrkEmp',
'd-VrkdaAcUsrCrd', 'Disable-VrkdaAcUsrCrd', 'd-VrkdaAcUsrLPR',
'Disable-VrkdaAcUsrLPR', 'e-VrkdaAcUsrCrd', 'Enable-VrkdaAcUsrCrd',
Expand All @@ -150,26 +153,27 @@ AliasesToExport = 'a-VrkdaAcGrp', 'Add-VrkdaAcGrp', 'a-VrkdaAcUsrCrd',
'Remove-VrkdaAcUsrCrd', 'rm-VrkdaAcUsrCrd',
'Remove-VrkdaAcUsrEntryCo', 'rm-VrkdaAcUsrEntryCo',
'Remove-VrkdaAcUsrFrGrp', 'rm-VrkdaAcUsrFrGrp',
'Remove-VrkdaAcUsrLPR', 'rm-VrkdaAcUsrLPR',
'Remove-VrkdaAcUsrPrflPic', 'rm-VrkdaAcUsrPrflPic',
'Remove-VrkdaAcUsrRmtUnlk', 'rm-VrkdaAcUsrRmtUnlk',
'Remove-VrkdaCamArchv', 'rm-VrkdaCamArchv', 'Remove-VrkdaCmdUsr',
'rm-VrkdaCmdUsr', 'Remove-VrkdaHlxEvt', 'rm-VrkdaHlxEvt',
'Remove-VerkadaLPoI', 'Remove-VrkdaWrkEmp', 'rm-VrkdaWrkEmp',
'sd-VrkdaPssInv', 'Send-VrkdaPssInv', 'Set-VrkdaAcDrNm',
'st-VrkdaAcDrNm', 's-VrkdAcDrSchOvrd', 'Set-VrkdAcDrSchOvrd',
'Set-VrkdaAcUsrBtUnlk', 'st-VrkdaAcUsrBtUnlk', 'Set-VrkdaAcUsrEndDt',
'st-VrkdaAcUsrEndDt', 'Set-VrkdaAcUsrEntryCo', 'st-VrkdaAcUsrEntryCo',
'Set-VrkdaAcUsrGrp', 'st-VrkdaAcUsrGrp', 's-VrkdaAcUsrPrflPic',
'Set-VrkdaAcUsrPrflPic', 'Set-VrkdaAcUsrRmtUnlk',
'st-VrkdaAcUsrRmtUnlk', 'Set-VrkdaAcUsrStrtDt', 'st-VrkdaAcUsrStrtDt',
's-VrkdAlrmBr31Setgs', 's-VrkdAlrmDrSenSetgs',
'Set-VrkdAlrmDrSenSetgs', 's-VrkdAlrmBr33Setgs',
's-VrkdAlrmPancSetgs', 'Set-VrkdAlrmPancSetgs', 'Set-VrkdaCamOrnt',
'VrkdaCamOrnt', 'Set-VrkdaCamTmprSen', 'VrkdaCamTmprSen',
'Set-VrkdaCmdUsr', 'st-VrkdaCmdUsr', 'Set-VrkdaHlxEvt',
'st-VrkdaHlxEvt', 'Set-VerkadaLPoI', 'Set-VrkdaWrkEmp',
'st-VrkdaWrkEmp', 'uk-VrkdAcDoor', 'Unlock-VrkdAcDoor'
'Remove-VrkdaAcUsrLPR', 'rm-VrkdaAcUsrLPR', 'Remove-VrkdaAcUsrMfaCd',
'rm-VrkdaAcUsrMfaCd', 'Remove-VrkdaAcUsrPrflPic',
'rm-VrkdaAcUsrPrflPic', 'Remove-VrkdaAcUsrRmtUnlk',
'rm-VrkdaAcUsrRmtUnlk', 'Remove-VrkdaCamArchv', 'rm-VrkdaCamArchv',
'Remove-VrkdaCmdUsr', 'rm-VrkdaCmdUsr', 'Remove-VrkdaHlxEvt',
'rm-VrkdaHlxEvt', 'Remove-VerkadaLPoI', 'Remove-VrkdaWrkEmp',
'rm-VrkdaWrkEmp', 'sd-VrkdaPssInv', 'Send-VrkdaPssInv',
'Set-VrkdaAcDrNm', 'st-VrkdaAcDrNm', 's-VrkdAcDrSchOvrd',
'Set-VrkdAcDrSchOvrd', 'Set-VrkdaAcUsrBtUnlk', 'st-VrkdaAcUsrBtUnlk',
'Set-VrkdaAcUsrEndDt', 'st-VrkdaAcUsrEndDt', 'Set-VrkdaAcUsrEntryCo',
'st-VrkdaAcUsrEntryCo', 'Set-VrkdaAcUsrGrp', 'st-VrkdaAcUsrGrp',
's-VrkdaAcUsrPrflPic', 'Set-VrkdaAcUsrPrflPic',
'Set-VrkdaAcUsrRmtUnlk', 'st-VrkdaAcUsrRmtUnlk',
'Set-VrkdaAcUsrStrtDt', 'st-VrkdaAcUsrStrtDt', 's-VrkdAlrmBr31Setgs',
's-VrkdAlrmDrSenSetgs', 'Set-VrkdAlrmDrSenSetgs',
's-VrkdAlrmBr33Setgs', 's-VrkdAlrmPancSetgs', 'Set-VrkdAlrmPancSetgs',
'Set-VrkdaCamOrnt', 'VrkdaCamOrnt', 'Set-VrkdaCamTmprSen',
'VrkdaCamTmprSen', 'Set-VrkdaCmdUsr', 'st-VrkdaCmdUsr',
'Set-VrkdaHlxEvt', 'st-VrkdaHlxEvt', 'Set-VerkadaLPoI',
'Set-VrkdaWrkEmp', 'st-VrkdaWrkEmp', 'uk-VrkdAcDoor',
'Unlock-VrkdAcDoor'

# DSC resources to export from this module
# DscResourcesToExport = @()
Expand Down