mirror of
https://github.com/Micke-K/IntuneManagement.git
synced 2026-09-28 19:05:38 +02:00
120 lines
7.2 KiB
Markdown
120 lines
7.2 KiB
Markdown
# Atlassian (Confluence) documentation output
|
|
|
|
[`Internal/Documentation/OutputProviders/DocumentationOutputAtlassian.ps1`](../Internal/Documentation/OutputProviders/DocumentationOutputAtlassian.ps1)
|
|
|
|
Emits Confluence **storage format** (XHTML plus `<ac:*>` macros) for a documentation
|
|
run: paste it into a page's *Rich Text -> Source* view, or POST it to the Confluence
|
|
REST API as `representation=storage`. Structurally it mirrors the HTML provider
|
|
(BasicInfo / FilteredSettings / ComplianceActions / ApplicabilityRules / Assignments /
|
|
CustomTables plus a per-run table of contents); only the markup differs.
|
|
|
|
Select it with `-OutputFormat atlassian`.
|
|
|
|
| Option (`$Options.Outputs.atlassian`) | Default | Meaning |
|
|
| --- | --- | --- |
|
|
| `AtlassianDocumentName` | `%MyDocuments%\%Organization%-%Date%.html` | Output path. Supports `Expand-FileName` tokens. |
|
|
| `AtlassianDocumentFileType` | `Full` | `Full` = one file; `Object` = one file per policy plus a TOC index file. |
|
|
| `AtlassianTitleProperty` | `Intune documentation` | `<h1>` of the index page. |
|
|
| `AtlassianOpenFile` | `$true` | Launch the file with the OS default handler. Set `$false` for CI. |
|
|
|
|
## Heading anchors (a consumer contract)
|
|
|
|
Every heading is emitted with an inline anchor macro:
|
|
|
|
```xml
|
|
<h4 id='section-42'><ac:structured-macro ac:name='anchor' ac:schema-version='1'><ac:parameter ac:name=''>section-42</ac:parameter></ac:structured-macro>Contoso Reader</h4>
|
|
```
|
|
|
|
The anchor name has appeared as literal `<!--#section-N-->` text downstream of the
|
|
generated file. The source of that rewrite is still unproven: the publishing runbook
|
|
parses the body with mshtml before POSTing, and Confluence also transforms storage
|
|
format. The inline placement remains the known baseline until those paths are measured
|
|
separately.
|
|
|
|
Three properties are guaranteed, and downstream tooling depends on them:
|
|
|
|
1. **The `anchor` macro carries the link target.** Confluence discards author-specified
|
|
`id=` attributes when it converts storage format to ADF, so `#section-42` can only
|
|
resolve to an anchor macro or to Confluence's own heading-text-derived anchor.
|
|
2. **`id=` always equals the macro name, byte for byte.** Confluence strips it, but
|
|
automation that parses the *generated file* before publishing reads the anchor from
|
|
it - for example to walk an assignment table cell back to its policy heading and
|
|
build a deep link into the published page.
|
|
3. **The table of contents links these names, never the heading text.** Anchor names
|
|
contain no character that came from tenant data.
|
|
|
|
**Naming scheme (breaking-change surface):** `section-N` for every heading, numbered
|
|
in emission order over the whole run. `section-N` is unique across a run even in
|
|
`Object` mode, because the counter is reset only in
|
|
`Invoke-AtlassianPreProcessItems`. Numbering is *not contiguous within the TOC*: a
|
|
heading consumes a number whenever it is written to the document, including the
|
|
level-6 table captions that the TOC's level cap (4) filters out and the `-SkipTOC`
|
|
script captions it never lists. Do not assume contiguity - and do not reconstruct the
|
|
numbers by counting TOC entries.
|
|
|
|
`table-N` is reserved for the `-ToT` caption form of `Add-AtlassianHeader`, which no
|
|
call site in this provider uses: table captions here are plain level-6 headings, as
|
|
in the HTML provider. Only the Markdown provider passes `-ToT` (and so is the only
|
|
output with visible `Table N.` numbering). Enabling it for Atlassian would change
|
|
rendered captions, so it belongs with the HTML provider as one formatting decision
|
|
rather than a port detail.
|
|
|
|
The scheme is positional, so inserting one policy shifts every later anchor: links a
|
|
user saved from an earlier run of a scheduled export therefore move. A content-derived
|
|
scheme (`policy-<objectId>` from the Graph GUID) would be stable and is the natural
|
|
follow-up; it needs `Add-AtlassianHeader` to accept an explicit anchor from
|
|
`Invoke-AtlassianProcessItem`, with the positional counter kept as the fallback for
|
|
headers that have no natural identifier.
|
|
|
|
**Deployment ordering:** update the module wherever the export runs *before* a consumer
|
|
switches to reading `id=` / linking `#section-N`, or its links will point at anchors
|
|
that do not exist yet.
|
|
|
|
## Markup constraints
|
|
|
|
- **Single-quote every attribute.** Consumers JSON-escape the document body before a
|
|
Confluence client serialises it again; a double-quoted attribute arrives as
|
|
`ac:name=\"anchor\"` and breaks the macro. Every macro in the provider follows this,
|
|
so the body survives a JSON round-trip byte-identically.
|
|
- **Storage format is strict XML** and declares only the five XML built-in entities.
|
|
Use numeric references (` `, never ` `), close every macro, and escape
|
|
text that comes from the tenant - `Get-AtlassianXmlText` for headings, TOC labels,
|
|
the title and the document-info lines; `Set-AtlassianText` for table cell values
|
|
(it also wraps XML-looking values in a `code` macro and long text in an `expand`).
|
|
A single bare `&` in a policy name invalidates the whole page body, not one heading,
|
|
and Confluence rejects the upload.
|
|
- **In `Object` mode the TOC's `href` carries a file name derived from a policy
|
|
name.** `Get-AtlassianObjectFileName` strips only path-invalid characters, so `&`,
|
|
`'` and `#` survive into it. `Get-AtlassianHref` percent-encodes the file-name
|
|
component (never the `#` that introduces the fragment) and then XML-escapes the
|
|
result; use it rather than interpolating a file name into an attribute.
|
|
|
|
## Change history
|
|
|
|
Unreleased (part of 4.0, no shipped version has the earlier behaviour):
|
|
|
|
- Table of contents entries link the anchor macro each heading emits. They used to
|
|
target a fragment re-derived from the heading text, so duplicate policy names all
|
|
jumped to the first occurrence and characters other than a plain space (`.`, `(`,
|
|
`)`, `:`, `&`, `+`, `,`, U+00A0) leaked into the href unencoded.
|
|
- Headings carry an inline `anchor` macro; previously they carried only an `id=` that
|
|
Confluence discards, which nothing could link to. The *shape* of an anchor name is
|
|
unchanged (`section-N`), so a consumer reading `id=` needs no update. A provisional
|
|
preceding-paragraph placement was reverted before release because its downstream
|
|
behavior and blank-line cost had not been measured.
|
|
- A heading kept out of the TOC now consumes an anchor number. It used to reuse the
|
|
next listed heading's number, so a document containing script captions (Detection
|
|
script, Requirement scripts) emitted two `section-N` anchors with one name and the
|
|
TOC entry landed on the caption. This shifts the numbers in such documents: another
|
|
reason to read `id=` rather than compute `section-N` from a position.
|
|
- Object-mode `href` file names are percent-encoded. A policy name containing `&`
|
|
or `'` used to produce a malformed body, and one containing `#` a link to the wrong
|
|
fragment.
|
|
- In the `-ToT` caption path (present but unused, see above) the `Table N. ` prefix
|
|
moved from the id to the visible text, where the Markdown provider puts it.
|
|
- Heading text, TOC labels, the title and the document-info lines are XML-escaped.
|
|
- Confluence keeps generating its own text-derived anchors, so externally saved
|
|
`#Policy-Name` links still resolve.
|
|
|
|
The three guarantees above are covered by the project's own test suite.
|