Skip to content

feat: Add SecureString support to Get-D365LcsApiToken -Password param#906

Merged
FH-Inway merged 12 commits into
d365collaborative:masterfrom
pavankadabala-png:fix/673-get-d365lcsapitoken-securestring
Jun 28, 2026
Merged

feat: Add SecureString support to Get-D365LcsApiToken -Password param#906
FH-Inway merged 12 commits into
d365collaborative:masterfrom
pavankadabala-png:fix/673-get-d365lcsapitoken-securestring

Conversation

@pavankadabala-png

Copy link
Copy Markdown
Contributor

Closes #673

What this changes

-Password previously accepted [string], which triggered the PSAvoidUsingPlainTextForPassword analyzer rule and exposed credentials in plain text in memory. This PR changes it to [securestring] while preserving full backward compatibility.

How it works

SecureStringTransformAttribute class (new, defined above the function):
A custom ArgumentTransformationAttribute that intercepts the -Password binding. If a plain [string] is passed, it silently converts it to a [securestring] via ConvertTo-SecureString. If a [securestring] is already provided, it passes through unchanged. This means no existing scripts need to be updated.

Plaintext recovery before Invoke-PasswordGrant:
The OAuth grant flow still requires a plaintext credential. One line converts the SecureString back to plaintext just before the call using the standard [System.Net.NetworkCredential] idiom, which is the accepted safe pattern for this scenario:

$plainTextPassword = [System.Net.NetworkCredential]::new("", $Password).Password

Summary of changes

  • Add SecureStringTransformAttribute class above the function
  • Change -Password type from [string] to [securestring], decorated with [SecureStringTransform()]
  • Add $plainTextPassword conversion line; pass it to Invoke-PasswordGrant instead of $Password
  • Remove PSAvoidUsingPlainTextForPassword suppression (no longer needed)
  • Update .PARAMETER Password CBH to document dual-type support
  • Add new .EXAMPLE showing Read-Host -AsSecureString usage

Backward compatibility

No breaking changes. Callers using -Password "plaintext" continue to work identically — the argument transform handles the conversion transparently before PowerShell binds the parameter.

pavankadabala-png and others added 7 commits June 18, 2026 11:39
Fixes d365collaborative#673. Changes:
- Add SecureStringTransformAttribute class that auto-converts a plain
  [string] to [securestring], preserving backward compatibility for
    existing callers passing -Password "plaintext"
    - Change -Password parameter type from [string] to [securestring]
    - Convert SecureString back to plaintext via NetworkCredential before
      passing to Invoke-PasswordGrant
      - Remove PSAvoidUsingPlainTextForPassword suppression (no longer needed)
      - Update .PARAMETER Password CBH with dual-type guidance
      - Add new .EXAMPLE showing Read-Host -AsSecureString usage
Fixes d365collaborative#673. Changes:
- Add SecureStringTransformAttribute class that auto-converts a plain
  [string] to [securestring], preserving backward compatibility for
    existing callers passing -Password "plaintext"
    - Change -Password parameter type from [string] to [securestring]
    - Convert SecureString back to plaintext via NetworkCredential before
      passing to Invoke-PasswordGrant
      - Remove PSAvoidUsingPlainTextForPassword suppression (no longer needed)
      - Update .PARAMETER Password CBH with dual-type guidance
      - Add new .EXAMPLE showing Read-Host -AsSecureString usage
Error: Cannot find the type for custom attribute 'SecureStringTransform'. Make sure that the assembly that contains this type is loaded.
The custom attribute to transform the string password into a secure string is not included in the mock that Pester creates for the function.
We intentionally accept plain text passwords for backward compatibility and ease of use.
This pull request was automatically created by the d365fo.tools-Generate-Text action'
@FH-Inway

Copy link
Copy Markdown
Member

When I first tested this, I got the following error:

Error: Cannot find the type for custom attribute 'SecureStringTransform'. Make sure that the assembly that contains this type is loaded.

After changing the name of the attribute to SecureStringTransformAttribute, it started working - not sure why the Attribute part is needed here, normally it can be dropped.

After that, it turned out that the approach is incompatible with the unit testing framework Pester. We use that to run all kinds of tests against the functions. One of them validates the examples from the function documentation. This is not a full functional test. Instead, Pester creates a mock of the function and then validates that the command itself is valid. Unfortunately, the way the mock is created does not support custom attributes (see pester/Pester#1772 for a related issue).

So I excluded Get-D365LcsApiToken from the generic example tests and wrote a custom test script for it.

Note I also rebased on the latest master to include the fixes for the default values of mandatory parameters.

I created pr pavankadabala-png#2 for those changes, targeting your feature branch. Note it currently says there is a conflict. You can ignore that and reset your branch to the tip of my branch. Afterwards, the checks for this pull request should be successful.

@Splaxi

Splaxi commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

There is a typo:

enhvironment

@FH-Inway FH-Inway merged commit 379d26c into d365collaborative:master Jun 28, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Get-D365LcsApiToken should accept secure string for password

3 participants