﻿#This script is provided as a base framework and may need additional changes to work in your environment.
#Current this is designed to bring in users from a csv file, but this could be changed for other mediums of input.

# Update lines 6-10 to get started!

$fqdn = "your-appliance-fqdn" # example "demo.labsystem.com"
$token = "admin-or-configuration-level-api-token" # example "1It8mrR0us6tpI9SjTO0mdB_EBL0EuO_RkCU69GOGZs"
$csvAccountRows = import-csv "C:\users\username\downloads\password.csv" # put .csv path to import here
$roleName = "AdminRole" # Name of the desired Role to set at creation
$updateRole = $false # When updating an existing account, should we replace the RoleId or leave it alone?


# Using version v8-preview for Role support
$apiVersion = "v8-preview"

# WARNING: This is needed to ignoring SSL/TLS certificate errors but is a security risk
#-------------------------------------------------------------------------------------------------------
$code = @"
public class SSLHandler
{public static System.Net.Security.RemoteCertificateValidationCallback GetSSLHandler()
    {return new System.Net.Security.RemoteCertificateValidationCallback((sender, certificate, chain, policyErrors) => { return true; });}
}
"@
Add-Type -TypeDefinition $code
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = [SSLHandler]::GetSSLHandler()
#-------------------------------------------------------------------------------------------------------

## The Get-RoleID function grabs all of the existing roles and compares the configured name ($RoleName) with the list
## If the configured name is found in the list it returns the ID of that account group ($global:RoleID)
function get-RoleID {
    Param (
	[Parameter(Mandatory = $true)][string]$RoleName
    )
    
    if (-not $RoleName) {
        return $null
    }
    try {
	# If the name is already a UUID, just use that
        $throwaway = [guid]$RoleName
        Write-Host "Using $($RoleName) as RoleID"
        return $RoleName
    } catch {
        # Otherwise proceed with the lookup
    }
    #Parameters of the API command that combines all values and selects the target API
    $Parameters     = @{
        Uri         = 'https://' + $fqdn + '/publicApi/v8-preview/auth/roles/'
        Headers     = $Header
        Method      = 'GET'
        body        = $Body
        ContentType = 'application/json'
    }

    #Execute the command using the parameters and placing them in the $request object.
    $request = Invoke-RestMethod @Parameters

    #setting counter to 0
    $i=0

    $RoldID = $null
    #Go through the array of items generated by the rest command
    ForEach ($item in $request.items)
    {
        $i++
        # Check each entry in array to check if the configured name exists in the array, if not it does nothing.
        If($item.name -like $RoleName){
           $RoleID = $item.id
           Write-Host 'Found Role match:'$item.id
           Break
        }
        
        # if the end of the array is reached and no match is found, report and continue    
        ElseIf($i -ge $request.items.count){
            Write-Host 'No Role name match found for'$RoleName ', Continuing script...'
            # set value to null so test is still created without an account group
            $RoleID = $null
        }

    }
    return $RoleID
}

Function Update-RoleID{

    Param (    
        [Parameter(Mandatory = $true)][string]$accountId,
	[Parameter(Mandatory = $true)][string]$roleId 
	)


	$Header = @{
		"Accept"        = "application/json"
		"Authorization" = "Bearer $token"
	}
	$Parameters = @{
		Uri         = 'https://' + $fqdn + '/publicApi/' + $apiVersion + '/accounts/' + $accountid + '/access'
		Headers     = $header
		Method      = 'PUT'
        	Body = '[ "' + $roleId + '" ]'
		ContentType = 'application/json'
	}

	$response = Invoke-RestMethod @Parameters
}



function CreateAccounts-FromCSV {
	Param (
		[Parameter(Mandatory = $true)][string]$username,
		[Parameter(Mandatory = $true)][string]$domainId,
		[Parameter(Mandatory = $true)][string]$password,
		[Parameter(Mandatory = $true)][string]$email,
		[Parameter(Mandatory = $true)][string]$roleId
	)
	
	# WARNING: ignoring SSL/TLS certificate errors is a security risk
    [System.Net.ServicePointManager]::ServerCertificateValidationCallback = [SSLHandler]::GetSSLHandler()
	
	$Body = @{
	  username = $username
	  Domain = $domainId
	  password = $password
	  email = $email
	  roles = @($roleId)
	} | ConvertTo-Json

	$Header = @{
		"Accept"        = "application/json"
		"Authorization" = "Bearer $token"
	}

	$Parameters = @{
		Uri         = 'https://' + $fqdn + '/publicApi/' + $apiVersion + '/accounts' # might have to use '/publicApi/' + $apiVersion + '/accounts' depending on LE version
		Headers     = $header
		Method      = 'POST'
		Body        = $Body
		ContentType = 'application/json'
	}

	$Response = Invoke-RestMethod @Parameters
	$Response
}

Function Update-Password{

    Param (    
        [Parameter(Mandatory = $true)][string]$user,
        [Parameter(Mandatory = $true)][string]$accountid,
	[Parameter(Mandatory = $true)][string]$domainId,
	[Parameter(Mandatory = $true)][string]$password,
	[Parameter(Mandatory = $true)][string]$email 
	)

	$body =  @{
	  Username = $user
	  password = $password
	  domain = $domainId
	  email = $email
          
	} | ConvertTo-Json

	$Header = @{
		"Accept"        = "application/json"
		"Authorization" = "Bearer $token"
	}
	$Parameters = @{
		Uri         = 'https://' + $fqdn + '/publicApi/' + $apiVersion + '/accounts/' + $accountid
		Headers     = $header
		Method      = 'PUT'
        Body = $body
		ContentType = 'application/json'
	}

	$response = Invoke-RestMethod @Parameters
}

#Begin script logic, by gathering account information

$Header = @{
		"Accept"        = "application/json"
		"Authorization" = "Bearer $token"
	}

$Parameters = @{
		Uri         = 'https://' + $fqdn + '/publicApi/' + $apiVersion + '/accounts?count=1000' # might have to use '/publicApi/' + $apiVersion + '/accounts' depending on LE version
		Headers     = $header
		Method      = 'GET'
		ContentType = 'application/json'
	}

$response = Invoke-RestMethod @Parameters

$userlist = $response.items.username

# Get the RoldID associated with the desired RoleName:

$roleId = Get-RoleID $roleName
if (-not $roleId) {
    write-host "Role $($roleName) is not found in the appliance.  Terminating."
    exit -1
}


#$result = $response.items | Where $_username -match $user
foreach ($csvAccountRow in $csvAccountRows){
	
       if($userlist -contains $csvAccountRow.accountNameColumn){
        write-host "User" $csvAccountRow.accountNameColumn "exists, updating password"
        $accountid = $response.items | Where-Object -Property username -Contains $csvAccountRow.accountNameColumn
        $id = $accountid.id
        Update-Password -user $csvAccountRow.accountNameColumn -accountid $id -domainId $csvAccountRow.domainColumn -password $csvAccountRow.passwordColumn $csvAccountRow.emailColumn
	if ($updateRole) {
	        Update-RoleId -accountid $id -roleId $roleId
	}
        } 
        else{
        write-host "Account" $csvAccountRow.accountNameColumn "not found, creating"
        CreateAccounts-FromCSV -username $csvAccountRow.accountNameColumn -domainId $csvAccountRow.domainColumn $csvAccountRow.passwordColumn $csvAccountRow.emailColumn $roleId
       }
}