Deep CRUD and Array Manipulation Engine
The auspex module provides the Invoke-Auspex function (aliases: auspex, ax), a robust engine for performing Deep CRUD (Create, Read, Update, Delete) and Array Manipulation (Push/Pull) on complex PowerShell data structures.
Unlike standard assignment, Auspex abstracts the underlying differences between Hashtables, PSObjects, Dictionaries, and Lists. It features a powerful Path Resolution Engine that allows you to traverse nested objects, index into arrays, and even select array items by value using a unified syntax (e.g., Servers[0].Network[Type='WAN'].IP).
🚨 Requirement: powershell 7.x
🧷 Examples 🧷 Cmdlet Reference 🧷 Data Accelerators 🧷 PSGallery 🧷 Chocolatey 🧷 GitHub📚 Table of Contents
- Deep Path Traversal: seamless dot-notation access (
Obj.Prop.Nested) across mixed object types. - Smart Array Indexing:
- Direct Index: Access specific items by position (e.g.,
Users[0]). - Muli-Path Index: Access specific items by multi-path position (e.g.,
Users[0].Network[Type=WAN].IP) - Multi-Property Matching: Target array items by multiple property values (e.g.,
Users[ID=105&Status=Active]) - Unified CRUD Operations:
- Create: Safely adds properties or dictionary keys only if they don't exist.
- Read: Retrieves values from deep within nested structures.
- Update: Modifies values regardless of whether the parent is a
Hashtable,PSObject, orList. - Delete: Removes properties, keys, or array items uniformly.
- Array Manipulation:
- Push: Appends values to arrays or generic lists.
- Pull: Removes specific values from arrays (filtering).
- Type Conversion: Converts data to the desired output format:
Convert-AxData -Type 'OrderedDictionary' - Type Accelerators:
New-AxPsco @{},New-AxPso @{},New-AxHt @{},New-AxDict @{},New-AxList @{} - Object Grapher: Visualizes objects and their properties in a tree-like structure**
- Auto-Type Detection: Automatically detects if the target container is a Dictionary, Object, or List and applies the correct .NET method (
.Add(),.Remove(), assignment, etc.). - Debug Logging: detailed, color-coded execution traces (Info, Warning, Error) via
$global:__logging.
Phellams modules are available from PowerShell Gallery and Chocolatey. you can access the raw assets via Gitlab Generic Assets or nuget repository via Gitlab Packages.
| ▓▓▓▓▒▒▒▒░░░ | ▓▓▓▓▒▒▒▒░░░ | ▓▓▓▓▒▒▒▒░░░ |
|---|---|---|
| 📦 PSGallery | |
|
| 📦 Chocolatey |
| ▓▓▓▓▒▒▒▒░░░ | ▓▓▓▓▒▒▒▒░░░ | ▓▓▓▓▒▒▒▒░░░ |
|---|---|---|
| 💼 Releases/Tags | |
|
Using nuget: See the packages page for installation instructions.
For instructions on adding
nugetsources packages from GitLab see Releases artifacts or via the Packages page.
The latest release artifacts can be downloaded from the Generic Assets Artifacts page.
# Clone the repository
git clone https://gitlab.com/phellams/auspex.git
cd auspex
import-module .\Module is self contained with-in a single .psm1 file and can be imported with Import-Module .\auspex.psd1 or using module .\auspex.psm1 if your using Auspex with another module i would suggest just copying the auspex.psm1 to your module folder and use using module path\to\auspex.psm1 or install Auspex from one of the methods above.
# Import the module
# Requires Find-Module -name auspex | install-module
Import-Module -Name Auspex
# Using with another module
# Copy the file to you module folder
using module .\auspex.psm1
# Create a data object
$data = [PSCustomObject]@{ NetworkName = 'Lan-room-1' }
# or use auspex
$data = axpsco @{ NetworkName = 'Lan-room-1' }
# Create a new property
auspex $data create 'Status' 'Active'
# Read the property
auspex $data read 'Status'
# Update the property
auspex $data update 'Status' 'In-Active'
# Delete the property
auspex $data delete 'Status'
This is the main function exposed by the module. It allows you to perform CRUD operations on Hashtables, PSObjects, Dictionaries, and Lists, push and pull actions for objects and arrays.
Aliases: ax auspex
Syntax
Invoke-Auspex [-o|ObjectPointer (Object)]
[-a|Action (String(validateset(read,create,update,delete,push,pull))]
[-k|KeyName (String)]
[-va|Value (Any)]
[-l|Log (Switch)]
[-e|EmbeddedName (String)]
Parameters
| Name | Type | Description | Required |
|---|---|---|---|
| ObjectPointer | PSObject, PSCustomObject, Hashtable, Dictionary, SortedList | The target data structure to modify. | Yes |
| Action | String | The operation to perform: create, read, update, delete, push, pull |
Yes |
| Name | String | The property or key name to target. | Yes |
| Value | Any | The value to set (for create/update/push) or remove (for pull). Not required for read/delete. | No |
| log | switch | Enable logging | No |
| EmbeddedName | string | pre-apend a custom name to the log message | No |
✴️ Note ! ═══════ These parameters are positionally numbered so you can pass theme in without the ParameterName in order. eg:
auspex $data create 'Status' 'Active'or:ax $data create 'Status' 'Active'or:Invoke-Auspex $data create 'Status' 'Active'
✴️ Note ! ═══════ You can also work with the objects in reverse instead of using the
-KeyNameparameter with dot or array notation or both, you can simply source the object yourself and pass it in as the-ObjectPointerparameter. eg:Invoke-Auspex $data.Network create 'Status' 'Active'
🟢 Reading (Deep Access & Querying)
# 1. Simple Nested Read
auspex -Obj $Config -Action "read" -Name "System.Hostname"
# or shorthand
auspex -Obj $Config -Action "read" -Name "System.Hostname"
# 2. Array Indexing (Reading the 2nd DNS server)
auspex -Obj $Config -Action "read" -Name "Network.DNS[1]"
# 3. COMPLEX: Query Match (Find the IP of the interface named 'eth1')
# Logic: Go to Network -> Go to Interfaces -> Find Item where Name='eth1' -> Get IP
auspex -Obj $Config -Action "read" -Name "Network.Interfaces[Name='eth1'].IP"
🔵 Updating (Modify Existing)
Modify values deep inside the structure using the same path logic.
# 1. Update a HashTable value via Index
auspex -Obj $Config -Action "update" -Name "Network.DNS[0]" -Value "9.9.9.9"
# 2. Update a Property found via Query Match
# We are enabling eth1
auspex -Obj $Config -Action "update" -Name "Network.Interfaces[Name='eth1'].Active" -Value $true
# Verify Update
$Config.Network.Interfaces[1]
🟣 Creating (Building New Properties)
This uses the logic to add keys to Hashtables or NoteProperties to PSObjects.
# 1. Add a new property to the System PSObject
auspex -Obj $Config -Action "create" -Name "System.Kernel" -Value "5.15-generic"
# 2. Add a new Key to the Network Hashtable
auspex -Obj $Config -Action "create" -Name "Network.Gateway" -Value "192.168.1.1"
# Verify
$Config.System
$Config.Network.Gateway
🟡 Pushing (Array Appending)
This adds items to arrays or generic lists.
Write-Host "`n--- PUSH EXAMPLES ---" -ForegroundColor Magenta
# 1. Push to a Generic List<string> (Tags)
auspex -Obj $Config -Name "Tags" -Action "push" -Value "HighPriority"
# 2. Push a new Object to an Array of Hashtables
$NewInterface = @{ Name = "docker0"; IP = "172.17.0.1"; Active = $true }
auspex -Obj $Config -Name "Network.Interfaces" -Action "push" -Value $NewInterface
# Verify
$Config.Tags
Write-Host "Interface Count: $($Config.Network.Interfaces.Count)"
🔴 Pulling & Deleting
Removing items from arrays (Pull) or removing properties/keys entirely (Delete).
Write-Host "`n--- DELETE/PULL EXAMPLES ---" -ForegroundColor Magenta
# 1. PULL: Remove "Web" from Tags list
auspex -Obj $Config -Name "Tags" -Action "pull" -Value "Web"
# 2. DELETE: Remove the 'OS' property from System
auspex -Obj $Config -Name "System.OS" -Action "delete"
# 3. DELETE (Advanced): Remove a specific interface by Index
# Note: Since Interfaces is a fixed array @(), this might fail in standard PS arrays
# unless the logic re-creates the array (which we did not implement for Delete, only Pull).
# However, let's delete the 'Gateway' key we added to the Hashtable earlier.
auspex -Obj $Config -Name "Network.Gateway" -Action "delete"
# Verify
$Config.Tags
$Config.System
🟣 Output Graph top level object
auspex -Obj $Config -Grapher🟣 Output Graph from nested object
auspex -Obj $Config -Name "Network.Interfaces" -GrapherThis function supports converting from any dictionary or object type to any of the six specific output formats you requested and automatically detects and normalizes data from:
[Hashtable][OrderedDictionary]- Ordered hashtable are SortedDictionaries[PSCustomObject][PSObject][System.Collections.Generic.Dictionary][System.Collections.SortedList]
Supported Data Types
| Types | Output .NET Type | Best Used For |
|---|---|---|
| hashtable | [System.Collections.Hashtable] |
Legacy compatibility, unsorted high-speed lookups. |
| Hashtable-Ordered | System.Collections.Specialized.OrderedDictionary |
Preserving key order (JSON generation, readable configs). |
| PSObject | PSCustomObject |
Standard PowerShell pipeline usage, display formatting. |
| PSCustomObject | PSCustomObject |
(Alias for PSObject). |
| SortedList | System.Collections.SortedList |
Automatically sorting keys alphabetically (A-Z). |
| Dictionary | System.Collections.Generic.Dictionary[string,object] |
Strictly typed keys, high performance in C# interop. |
Convert a Hashtable to a Ordered Hashtable
$hash = @{ c=3; a=1; b=2 }
$ordered = $hash | Convert-AxData -Type 'Hashtable-Ordered'
# Output will be automatically sorted: a=1, b=2, c=3
Convert a Hashtable to a SortedList:
$hash = @{ c=3; a=1; b=2 }
$sorted = $hash | Convert-AxData -Type 'SortedList'
# Output will be automatically sorted: a=1, b=2, c=3
Convert a PSObject to a standard Dictionary:
$obj = [PSCustomObject]@{ ID=1; Name="Admin" }
$dict = $obj | Convert-AxData -Type 'Dictionary'
# Result is a Dictionary[string,object]
Enable logging globally:
$global:__logging = $trueDisable logging globally:
$global:__logging = $falseEnable logging via param
auspex -Obj $data -Action create -Name 'Status' -Value 'Active' -logNote!:
auspexoraxorInvoke-Auspexyou can ommit the-ObjectPointer,-Name,-Actionand-Valueparameters, these parameters are positionally numbered so you can pass theme in without the-ParameterNamein order.
Run this block first to initialize the environment and the test data.
# --- Test Data Construction ---
# We are mixing Hashtables, PSObjects, and Arrays to test robustness
$Config = [PSCustomObject]@{
System = [PSCustomObject]@{
Hostname = "SKG-Blade-01"
OS = "Ubuntu 22.04"
}
Network = @{ # Hashtable
Interfaces = @(
@{ Name = "eth0"; IP = "192.168.1.10"; Active = $true }
@{ Name = "eth1"; IP = "10.0.0.5"; Active = $false }
)
DNS = @("8.8.8.8", "1.1.1.1")
}
Tags = [System.Collections.Generic.List[string]]::new() # Generic List
}
$Config.Tags.Add("Production")
$Config.Tags.Add("Web")
Auspex uses a special string syntax to locate items deep inside your objects.
| Syntax | Description | Example |
|---|---|---|
| Dot Notation | Access a property or key by name. | System.Network.IP |
| Index Notation | Access an array or list item by its integer index. | Servers[0] |
| Query Match | Find an item in an array where a property equals a specific value. | Users[Name='Admin'] |
| Combined | Chain any of the above to reach deep values. | Datacenter.Racks[0].Servers[ID='Web01'].State |
Example of Query Match: If you have a list of users and want to update the role for "Alice":
# Instead of looping through the array...
ax -Obj $Data -Name "Users[Name='Alice'].Role" -Action Update -Value "Manager"
New-Axpso
Alias: axpso
Generates a PSObject from hashtable.
$pso = iminipso @{ prop1 = 'prop1value'; level = 1 }New-Axpsco
Alias: axpsco
Generates a PSCustomObject from hashtable.
$psco = axpsco @{ prop1 = 'prop1value'; level = 1 }New-Axht
Alias: axht
Generates a Hashtable from hashtable.
$psht = axht @{ prop1 = 'prop1value'; level = 1 }New-Axdic
Alias: axdic
Generates a System.Collections.Generic.Dictionary[string, object] from Hashtable.
$psdic = axdic @{ prop1 = 'prop1value'; level = 1 }New-axsl
Alias: axsl
Generates a System.Collections.SortedList from Hashtable.
$psdsl = axsl @{ prop1 = 'prop1value'; level = 1 }| Data Type | Create | Read | Update | Delete | Push/Pull Arrays | Nested Objects |
|---|---|---|---|---|---|---|
| Hashtable | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| PSObject | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| PSCustomObject | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Dictionary | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| SortedList | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Array Support: [string[]], [object[]], [int[]], [hashtable[]], [psobject[]], [pscustomobject[]]
# The Data parameter accepts pipeline input
$myHashtable = @{ Status = 'Active' }
$myHashtable | Invoke-Axpso -Obj $data -Action create -Name 'Count' -Value 100# At the start of your script
$global:__logging = $false
# All auspex calls will now run silentlyIf you see a warning about a property already existing when using create:
# Use update instead of create for existing properties
auspex -Obj $obj -Action update -Name 'ExistingProp' -Value 'NewValue'If you see a warning about a property not found when using update, read, or delete:
# Use create first to add the property
auspex -Obj $obj -Action create -Name 'NewProp' -Value 'Value'The push and pull actions require the property to be an array:
# First, create an array property
auspex -Obj $obj -Action create -Name 'Items' -Value @()
# Then push values to it
auspex -Obj $obj -Action push -Name 'Items' -Value 'Item1'- Add Support for Dictionary, SortedList
- Add comprehensive Pester tests
- Create module manifest (.psd1) with proper versioning
- Add support for Dictionary
- Optimize performance for large datasets
- Add
-WhatIfand-Confirmsupport
Contributions are welcome! Please fork the repository and submit a Merge Request (MR) targeting the develop branch.
-
Fork the Project Click the "Fork" button in the top right corner of the repository page.
-
Clone your Fork
git clone [https://gitlab.com/YOUR_USERNAME/pwsl.git](https://gitlab.com/YOUR_USERNAME/pwsl.git) cd pwslmerge_requests/new) -
Create a Feature Branch Ensure you base your work on the develop branch:
git switch develop git switch -c feature/AmazingFeature
-
Commit your Changes
git commit -m 'feat: Add some AmazingFeature' -
Push to the Branch
git push origin feature/AmazingFeature
-
Open a Merge Request
This project is licensed under the [MIT License] - see the LICENSE file for details.
