DK Plus cmdlets are designed to chain. A Get- cmdlet returns objects, and the Update-, Remove-, Save-, and Send- cmdlets take their identity from those objects by property name.
Find a record and change it in one line. This changes the customer of quote number 12345:
Get-Quote -Number 12345 | Update-Quote -Customer 10001
Get-Quote writes the quote with its UUID in Id. Update-Quote binds -Id from that property and sends only the customer.
More patterns:
# Block every customer of a group
Get-Customer -Group 99 -Take 1000 | Update-Customer -Blocked
# Delete products, previewing first
Get-Product -Group 99 | Where-Object Inactive | Remove-Product -WhatIf
# Delete selected projects: one confirmation covers the whole batch
Get-Project -Customer 10001 | Where-Object Name -like 'Test*' | Remove-Project
# Save the PDF of a found invoice
Get-Invoice 12345 | Save-InvoicePdf
# Delete selected lines of an order
(Get-Order -Id $id).Lines | Where-Object Sequence -eq 2 | Remove-OrderLine -WhatIf
Each piped object is one request. A failure for one object is written as a non-terminating error, and the next object still runs. See Safety and errors.
Tip: pipe into Remove- instead of looping. The Remove- cmdlets ask for confirmation. When you pipe objects straight into one (Get-Project ... | Where-Object Name -like 'X*' | Remove-Project), PowerShell asks once and [A] Yes to All covers the rest of the batch. Calling Remove-Project inside ForEach-Object starts a new cmdlet call for every item, so it prompts for every item. -WhatIf previews the batch without sending anything, and -Confirm:$false skips the prompt in scripts.
A cmdlet binds its identity (-Number, -Id, -ItemCode, and so on) from a piped object's property of the same name. A plain string or a [pscustomobject] with that property, such as a row from Import-Csv, works too:
Import-Csv customers.csv | Update-Customer -Group 02 -WhatIf
An object of a different DK Plus type is rejected for that object before any request. For example, a customer group piped into Remove-Customer does not bind its Number as a customer number.
Child records carry the identities their cmdlets need as extra properties. Contacts carry Customer and Contact, receivers carry Customer and Receiver, and document lines carry the document's UUID (OrderId, QuoteId, or RecurringSaleId) and their Sequence. That is why (Get-Order -Id $id).Lines | Update-OrderLine -Memo '' works.
A cmdlet that needs two identities, such as Remove-ProjectPhaseLink, binds both from a link object.
Unprocessed vendor invoices carry an Unprocessed marker ($true), so Get-VendorInvoice -Unprocessed | Save-VendorInvoiceAttachment uses the unprocessed endpoint automatically. The invoices that wait for your approval (Get-VendorInvoice -MyUnapproved) are unbooked and carry the same marker, so they are read as unprocessed invoices too.
Project transactions carry a RecordId property, so Get-ProjectTransaction -Project P-1001 | Get-ProjectTransactionMemo and ... | Update-ProjectTransactionMemo -Memo 'Reviewed' bind it. A project, a journal, or another DK Plus object that also has a RecordId is rejected for that object before any request.
The sales line cmdlets (New-OrderLine, Update-OrderLine, Remove-OrderLine, and the quote and recurring-sale equivalents) take the document from a piped document's Id or from a line's OrderId, QuoteId, or RecurringSaleId. A document or line of another kind is rejected for that object before any request, so a quote can never add a line to an order. Documents returned by New-Order, New-Quote, and New-RecurringSale pipe straight into the matching New-...Line cmdlet.
Field values such as -Email or -Blocked are never bound from the pipeline. They apply to every piped object.
Update- cmdlets send only what you ask to change. This matches the CLI and the .NET client:
| You write | What is sent |
|---|---|
| Parameter omitted | Nothing; the field is unchanged. |
-Reference $null |
Nothing; a bound $null also means unchanged. |
-Reference '' |
An empty string; the field is cleared. |
-ExchangeRate 0 |
0. |
-Blocked |
true. |
-Blocked:$false |
false. |
# Sets Email, clears Alias, leaves everything else
Update-Customer 10001 -Email '[email protected]' -Alias ''
Only text can be cleared with ''. For switches, use -Name:$false. Whether a collection you send (address lines, order lines) replaces or merges with the stored one is not confirmed for every resource; DK Plus stores address lines by position, so a line can only be changed together with the lines before it.
An update that sets nothing fails before any request with the error id DkPlus.NoMemberSet. This covers Update-Customer 10001, -InputObject @{}, @{ Name = $null }, and an empty JSON file.
-InputObject: hashtables and objectsFor members that have no field parameter, such as nested sections, pass a hashtable (or an ordered dictionary, a [pscustomobject], or the request object itself):
Update-Customer 10001 -InputObject @{ Credit = @{ CreditLimit = 500000 } }
New-Vendor -InputObject @{ Number = '0102'; Name = 'Example sf.'; Approvers = @{ Approver1 = 'JON' } }
# Order lines are changed through the document
Update-Order $id -InputObject @{ Lines = @(@{ Sequence = 1; Quantity = 2 }) }
Status = 'InProcess').$null is not sent, '' clears.--file. Read-only members and DK Plus wire spellings are rejected with a message that names the replacement, for example HeaderText1 instead of Text1.-InputObject is not read from the pipeline. Pipe the identity, and pass the hashtable as the parameter. Pass a read model (a customer object from Get-Customer) as -InputObject and the cmdlet tells you to use a hashtable, a JSON file, or a request object.-Path: JSON files-Path reads a JSON document with the same format and checks as devop-dk ... --file, so a file works with both tools:
New-Customer -Path ./customer.json -WhatIf
Update-Customer 10001 -Path ./customer-update.json
New-Webhook -Path ./webhook.json
-Path, -InputObject, and the field parameters are separate parameter sets. You choose one; they are never merged. Create a file by converting a hashtable:
@{ Number = '10003'; Name = 'Example hf.' } | ConvertTo-Json -Depth 5 | Set-Content ./customer.json
New-Customer -Path ./customer.json -WhatIf
Scripts must behave the same on an Icelandic machine and an English one. The module therefore does not use the current culture for parameter values:
. as the decimal point. '2.5' is 2.5; '2,5' is rejected with a clear error instead of becoming 25. Numeric values (2.5, [decimal]2.5) pass through unchanged.2026-10-12 (that day at +00:00) or a date-time with an offset such as 2026-10-12T08:00:00+00:00. A [datetime] or [datetimeoffset] value passes through; a [datetime] with no kind at midnight is treated as that date at +00:00.int or long parameter (a page number, a count, a record identifier, a journal -Parent) accepts a whole number with an optional sign. A string such as '1,000', '2.5', or '1e3' is rejected instead of becoming 1000, 2 or 1000, and a value outside the range is rejected too.ConvertTo-Json and the objects themselves are culture-independent. Only table labels follow your UI language.Line values follow the same rule. The -Line hashtables, objects, and Import-Csv rows of New-Invoice take numbers as plain decimals with .: '4.5' works and '4,5' is rejected, whatever the culture. Dates inside -InputObject and -Path documents are read like --file documents.
Get-Customer -Group 01 -ModifiedSince '2026-10-01'
Update-Vendor 0101 -Email [email protected]
New-VendorInvoice 0101 -Number A-1 -Date 2026-10-12 -DueDate 2026-11-12 -Amount 1250.5 -CurrencyCode ISK
Combine Import-Csv and hashtables to build documents:
$lines = Import-Csv count.csv | ForEach-Object {
@{ ItemCode = $_.ItemCode; Counted = [decimal]::Parse($_.Counted, [cultureinfo]::InvariantCulture); Warehouse = 'MAIN' }
}
New-InventoryCount -InputObject @{ Description = 'Q4 count'; Lines = $lines } -Confirm:$false
Use -WhatIf first on bulk updates and read Safety and errors for confirmation levels.