# Managing objects in CyberArk (now Idira) with PowerShell Desired State Configuration

[PowerShell Desired State Configuration (DSC)](https://docs.microsoft.com/de-de/powershell/scripting/dsc/overview?view=powershell-7.2) is a tool similar to Ansible, Puppet, and Chef that enables declaratively setting how an environment is configured. PowerShell DSC can be used to ensure [*resources*](https://docs.microsoft.com/en-us/powershell/dsc/concepts/resources?view=dsc-2.0) such as environmental variables, software, files, Active Directory users, and application-specific settings are either present or absent through the use of [*configurations*](https://docs.microsoft.com/en-us/powershell/dsc/concepts/configurations?view=dsc-2.0).

A few of the most obvious, CyberArk (now Idira)-related use cases for PowerShell DSC include making sure that the required software is installed after importing a [Universal Connector package](https://timschindler.blog/creating-cyberark-connection-component-connector-packages) or after [deploying a CPM plugin as part of a continuous deployment pipeline](https://timschindler.blog/continuous-deployment-of-cyberark-platforms-using-github-actions). It can be used to manage the rules within an `PSMConfigureAppLocker.xml` file or invoke the automated installation or upgrade processes for components.

Though with the [`CyberArkDsc` module](https://github.com/aaearon/CyberArkDsc), PowerShell DSC can also be used to manage CyberArk Vault objects such as safes, safe memberships, and accounts.

%[https://github.com/aaearon/CyberArkDsc] 

# Why use PowerShell DSC to manage Vault objects?

Using PowerShell DSC to manage Vault objects makes sense for the same reasons configuration management makes sense for infrastructure.

*   **Combat configuration drift** - Ensure accounts have the intended configurations long after they are created -- particularly useful in a test or lab environment where experimentation may lead to false settings and thus unintended consequences.
    
*   **Idempotency** - Safes, safe memberships, and accounts can be created and configured using scripts, the Password Upload Utility, or PACLI but running executing these when the objects already exist may produce different results or fail entirely.
    
*   **Treat Vault objects as code** - Like with infrastructure as code, Vault objects can be defined in configurations and these configurations can be stored in version control, be included in continuous deployment pipelines, or reviewed by other team members.
    
*   **Included in PowerShell 5.1 and above** - PowerShell DSC is included in PowerShell 5.1 and above which absolves the need to install to install more software, such as Python when dealing with Ansible.
    

# Using PowerShell DSC and `CyberArkDsc` to populate an empty Vault

One of the leading use cases for using PowerShell DSC together with CyberArk is that it can be used to quickly create accounts on target systems and onboard them into the Vault.

In the following section, a DSC configuration will be used to create Active Directory users, safes to store them in the Vault, assign the needed safe memberships to make the accounts accessible, and finally onboard the users into the safes with the needed reconcile accounts.

*Note: For the sake of brevity, knowledge of PowerShell DSC concepts and* [*terminology*](https://docs.microsoft.com/en-us/powershell/dsc/concepts/terminology?view=dsc-2.0) *such as resources and configurations is assumed.*

## Installing the `CyberArkDsc` and `ActiveDirectoryDsc` modules

Installing the `ActiveDirectoryDsc` module is straightforward as it can be installed from the PowerShell Gallery like any other PowerShell module. The [`ActiveDirectoryDsc` wiki](https://github.com/dsccommunity/ActiveDirectoryDsc/wiki/#getting-started) has information on getting started.

`CyberArkDsc` is not available in the PowerShell Gallery and needs to be manually installed. As by default configurations are executed under the `SYSTEM` account, `CyberArkDsc` needs to, along with it's dependency [`psPAS`](https://github.com/pspete/psPAS), exist in a non-user-specific folder location defined in `$env:PSModulePath` -- for example: `$env:ProgramFiles\WindowsPowerShell\Modules`.

We can use `Get-DscResource` to ensure that both DSC modules are installed correctly.

```powershell
PS > Get-DscResource | Where-Object {$_.Name -eq 'CYA_Account' -or $_.Name -eq 'ADUser'}

ImplementedAs   Name                      ModuleName                     Version    Properties
-------------   ----                      ----------                     -------    ----------
PowerShell      ADUser                    ActiveDirectoryDsc             6.2.0      {DomainName, UserName, AccountNotDelegated, All...
PowerShell      CYA_Account               CyberArkDsc                    0.0.2      {Address, AuthenticationType, Credential, Ensur...

PS >
```

## Writing our configuration

We will keep our DSC configuration relatively short and sweet. We already have LDAP integration configured for the Vault, a user that is in both Vault Admins and Domain Admins groups, and platforms created in the Vault that the accounts will be onboarded with so this just leaves us with:

1.  Creating two users in Active Directory, one to be used as a reconcile account.
    
2.  Adding the reconcile account as a member to the Domain Admins group in Active Directory so it can reconcile the other.
    
3.  Creating two safes to store the accounts in: one for the reconcile account, the other.
    
4.  Assigning a membership to each safe enabling an existing Active Directory group named `CyberArk Administrators` full permissions to the reconcile account safe and another, existing Active Directory group named `Windows Administrators` with list, retrieve, and use accounts to the other.
    
5.  Onboarding both accounts: The reconcile account will be onboarded with the password defined when creating it in Active Directory and the other account will be onboarded with the reconcile account defined as a linked account.
    

## Defining the base of our configuration

Each DSC resource in `CyberArkDsc` takes at least four parameters: `PvwaUrl`, `AuthenticationType`, `Credential`, and `SkipCertificateCheck.` We define these as parameters our configuration accepts. In addition, we define an `InitialPassword` parameter that will be used when creating the reconcile account's Active Directory user and when onboarding into CyberArk.

We will have a single node -- `localhost` -- as we will run the DSC configuration on the same machine we compile it on. Our resources will go inside it.

Both `Credential` and `InitialPassword` will be passed `PSCredential` objects. As this is a lab environment I will not go through the [effort to have the credentials be properly secured in the resulting, compiled configuration](https://docs.microsoft.com/en-us/powershell/dsc/configurations/configdatacredentials?view=dsc-1.1) so I set a switch to allow the passwords to be stored plaintext.

```powershell
Configuration CreateLab_Configuration {
    param(
        $PvwaUrl,
        $AuthenticationType,
        $Credential,
        $SkipCertificateCheck,

        $InitialPassword
    )

    Node localhost {

    }

}

$ConfigData = @{
    AllNodes = @(
        @{
            NodeName                    = 'localhost'
            PSDscAllowDomainUser        = $true
            PSDscAllowPlainTextPassword = $true
        }
    )
}

$VaultCredential = New-Object System.Management.Automation.PSCredential('allison', (ConvertTo-SecureString 'Password!' -AsPlainText -Force))
$Password = New-Object System.Management.Automation.PSCredential('banana', (ConvertTo-SecureString 'P@$$W0RD12345' -AsPlainText -Force))

$ConfigurationParameters = @{
    ConfigurationData    = $ConfigData

    PvwaUrl              = 'https://192.168.137.101'
    AuthenticationType   = 'LDAP'
    SkipCertificateCheck = $true
    Credential           = $VaultCredential
    InitialPassword      = $Password
}

CreateLab_Configuration @ConfigurationParameters
```

## Defining resources

Our configuration will have nine resources. Using documentation, our familiarity with managing Vault objects via `psPAS` and `Get-DscResource -Name ADUser,ADGroup,CYA_Account,CYA_Safe,CYA_SafeMember -Syntax` to know how to define each resource, our complete configuration looks like:

```powershell
Configuration CreateLab_Configuration {
    param(
        $PvwaUrl,
        $AuthenticationType,
        $Credential,
        $SkipCertificateCheck,

        $InitialPassword
    )

    Import-DscResource -ModuleName 'ActiveDirectoryDsc' -Name 'ADUser', 'ADGroup'
    Import-DscResource -ModuleName 'CyberArkDsc'

    Node 'localhost' {

        ADUser 'iosharp\windowsReconcile50' {
            Ensure     = 'Present'
            UserName   = 'windowsReconcile50'
            DomainName = 'iosharp.dev'
            Password   = $InitialPassword
            PasswordNeverResets =  $true

            Credential = $Credential
        }

        ADUser 'iosharp\windowsAdmin50' {
            Ensure     = 'Present'
            UserName   = 'windowsAdmin50'
            DomainName = 'iosharp.dev'
            Password   = $InitialPassword
            PasswordNeverResets =  $true

            Credential = $Credential
        }

        ADGroup 'Domain Admins' {
            Ensure           = 'Present'
            GroupName        = 'Domain Admins'
            MembersToInclude = 'windowsReconcile50'
            Credential       = $Credential

            DependsOn        = '[ADUser]iosharp\windowsReconcile50'
        }

        CYA_Safe 'WinRec50' {
            Ensure                = 'Present'

            SafeName              = 'WinRec50'
            Description           = 'Windows Reconcile Safe'
            ManagingCPM           = 'PasswordManager'
            NumberOfDaysRetention = '1'

            PvwaUrl               = $PvwaUrl
            AuthenticationType    = $AuthenticationType
            SkipCertificateCheck  = $SkipCertificateCheck
            Credential            = $Credential
        }

        CYA_Safe 'WinAdmins50' {
            Ensure                = 'Present'

            SafeName              = 'WinAdmins50'
            Description           = 'Windows Admins Safe'
            ManagingCPM           = 'PasswordManager'
            NumberOfDaysRetention = '1'

            PvwaUrl               = $PvwaUrl
            AuthenticationType    = $AuthenticationType
            SkipCertificateCheck  = $SkipCertificateCheck
            Credential            = $Credential
        }

        CYA_SafeMember 'WinRec\CyberArk Administrators' {
            Ensure                                 = 'Present'

            SafeName                               = 'WinRec50'
            MemberName                             = 'CyberArk Administrators'
            SearchIn                               = 'iosharp.dev'
            UseAccounts                            = $true
            RetrieveAccounts                       = $true
            ListAccounts                           = $true
            AddAccounts                            = $true
            UpdateAccountContent                   = $true
            UpdateAccountProperties                = $true
            InitiateCPMAccountManagementOperations = $true
            SpecifyNextAccountContent              = $true
            RenameAccounts                         = $true
            DeleteAccounts                         = $true
            UnlockAccounts                         = $true
            ManageSafe                             = $true
            ManageSafeMembers                      = $true
            BackupSafe                             = $true
            ViewAuditLog                           = $true
            ViewSafeMembers                        = $true
            AccessWithoutConfirmation              = $true
            CreateFolders                          = $true
            DeleteFolders                          = $true
            MoveAccountsAndFolders                 = $true
            RequestsAuthorizationLevel1            = $true
            RequestsAuthorizationLevel2            = $false

            PvwaUrl                                = $PvwaUrl
            AuthenticationType                     = $AuthenticationType
            SkipCertificateCheck                   = $SkipCertificateCheck
            Credential                             = $Credential

            DependsOn                              = '[CYA_Safe]WinRec50'
        }

        CYA_SafeMember 'WinAdmins\Windows Administrators' {
            Ensure               = 'Present'

            SafeName             = 'WinAdmins50'
            MemberName           = 'Windows Administrators'
            SearchIn             = 'iosharp.dev'
            UseAccounts          = $true
            RetrieveAccounts     = $true
            ListAccounts         = $true
            ViewSafeMembers      = $true

            PvwaUrl              = $PvwaUrl
            AuthenticationType   = $AuthenticationType
            SkipCertificateCheck = $SkipCertificateCheck
            Credential           = $Credential

            DependsOn            = '[CYA_Safe]WinAdmins50'
        }

        CYA_Account 'windowsReconcile50' {
            Ensure               = 'Present'
            UserName             = 'windowsReconcile50'
            Address              = 'iosharp.dev'
            PlatformId           = 'ioSHARPWindowsDomainReconcileAccount'
            SafeName             = 'WinRec50'
            Name                 = 'windowsReconcile50@iosharp.dev'
            Password             = $InitialPassword

            PvwaUrl              = 'https://192.168.137.101'
            AuthenticationType   = 'LDAP'
            SkipCertificateCheck = $true
            Credential           = $VaultCredential

            DependsOn            = '[CYA_Safe]WinRec50'
        }

        CYA_Account 'windowsAdmin50' {
            Ensure               = 'Present'
            UserName             = 'windowsAdmin50'
            Address              = 'iosharp.dev'
            PlatformId           = 'ioSHARPWindowsDomainAccount'
            SafeName             = 'WinAdmins50'
            Name                 = 'windowsAdmin50@iosharp.dev'
            ReconcileAccount     = @{
                Name   = 'windowsReconcile50@iosharp.dev'
                Safe   = 'WinRec50'
                Folder = 'root'
            }

            PvwaUrl              = 'https://192.168.137.101'
            AuthenticationType   = 'LDAP'
            SkipCertificateCheck = $true
            Credential           = $VaultCredential

            DependsOn            = '[CYA_Account]windowsReconcile50', '[CYA_Safe]WinAdmins50'

        }

    }
}

$ConfigData = @{
    AllNodes = @(
        @{
            NodeName                    = 'localhost'
            PSDscAllowDomainUser        = $true
            PSDscAllowPlainTextPassword = $true
        }
    )
}

$VaultCredential = New-Object System.Management.Automation.PSCredential('allison', (ConvertTo-SecureString 'Password!' -AsPlainText -Force))
$Password = New-Object System.Management.Automation.PSCredential('banana', (ConvertTo-SecureString 'P@$$W0RD12345' -AsPlainText -Force))

$ConfigurationParameters = @{
    ConfigurationData    = $ConfigData

    PvwaUrl              = 'https://192.168.137.101'
    AuthenticationType   = 'LDAP'
    SkipCertificateCheck = $true
    Credential           = $VaultCredential
    InitialPassword      = $Password
}

CreateLab_Configuration @ConfigurationParameters
```

## Compiling and running our configuration

We dot source our saved configuration file to compile it:

```powershell
PS C:\Users\Tim.IOSHARP\Desktop\DSC> . .\CreateLab.ps1


    Directory: C:\Users\Tim.IOSHARP\Desktop\DSC\CreateLab_Configuration


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        9/16/2022   7:43 PM          15494 localhost.mof


PS C:\Users\Tim.IOSHARP\Desktop\DSC>
```

We can use `Test-DscConfiguration` to see if our resources in their desired state.

```powershell
PS C:\Users\Tim.IOSHARP\Desktop\DSC> Test-DscConfiguration .\CreateLab_Configuration\ | Select-Object -ExpandProperty ResourcesNotInDesiredState | Select-Object ResourceId

ResourceId
----------
[ADUser]iosharp\windowsReconcile50
[ADUser]iosharp\windowsAdmin50
[ADGroup]Domain Admins
[CYA_Safe]WinRec50
[CYA_Safe]WinAdmins50
[CYA_SafeMember]WinRec\CyberArk Administrators
[CYA_SafeMember]WinAdmins\Windows Administrators
[CYA_Account]windowsReconcile50
[CYA_Account]windowsAdmin50


PS C:\Users\Tim.IOSHARP\Desktop\DSC>
```

No surprise, none of our resources are as they do not even exist.

From there, we can start the configuration using `Start-DscConfiguration` and passing the `Wait` parameter.

```powershell
PS C:\Users\Tim.IOSHARP\Desktop\DSC> Start-DscConfiguration .\CreateLab_Configuration\ -Wait
PS C:\Users\Tim.IOSHARP\Desktop\DSC>
```

We do not get any output from `Start-DscConfiguration` which is exactly what we want. Running `Test-DscConfiguration` but this time looking at resources in the desired state shows us all nine of them.

```powershell
PS C:\Users\Tim.IOSHARP\Desktop\DSC> Test-DscConfiguration .\CreateLab_Configuration\ | Select-Object -ExpandProperty ResourcesInDesiredState | Select-Object ResourceId

ResourceId
----------
[ADUser]iosharp\windowsReconcile50
[ADUser]iosharp\windowsAdmin50
[ADGroup]Domain Admins
[CYA_Safe]WinRec50
[CYA_Safe]WinAdmins50
[CYA_SafeMember]WinRec\CyberArk Administrators
[CYA_SafeMember]WinAdmins\Windows Administrators
[CYA_Account]windowsReconcile50
[CYA_Account]windowsAdmin50


PS C:\Users\Tim.IOSHARP\Desktop\DSC>
```

But what matters is what we see in CyberArk. Browsing to the PVWA, we see our two newly onboarded accounts in our newly created safes. `windowsAdmin50` has `windowsReconcile50` defined as it's reconcile just as we defined in our DSC configuration.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663355550955/wF-pLMLnp.png align="left")

# Changing existing Vault objects with PowerShell DSC

Our configuration creates the objects when they are missing but what happens if they already exist in some form?

We make small changes to our accounts -- change their names, unlink the reconcile account, different platform -- with the goal that running `Start-DscConfiguration` will adjust them back to what is defined in our configuration.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663496265835/-w2pRHmqu.png align="left")

A quick `Test-DscConfiguration` shows that DSC knows the accounts in the Vault are incorrect based on the configuration:

```powershell
PS C:\Users\Tim.IOSHARP\Desktop\DSC> Test-DscConfiguration .\CreateLab_Configuration\ | Select-Object -ExpandProperty ResourcesNotInDesiredState | Select-Object ResourceId

ResourceId
----------
[CYA_Account]windowsReconcile50
[CYA_Account]windowsAdmin50

PS C:\Users\Tim.IOSHARP\Desktop\DSC>
```

Simply running `Start-DscConfiguration` 'silently' adjusts the accounts in CyberArk to their desired configuration.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663581070966/J56czAoxV.png align="left")

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663581091383/wApMU8z6j.png align="left")

There we have it: the same configuration we used to create the Vault objects was used to correct them without having to do any changes.

The `CyberArkDsc` module can be found on GitHub. Currently it only has resources for safes, safe memberships, and accounts. Pull requests are welcome!

%[https://github.com/aaearon/CyberArkDsc]
