Skip to content

About

PowerShell module for managing Omada Identity (Cloud) data via web and OData endpoints, supporting OAuth2 and browser-based authentication.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

1 watching

Forks

Repository files navigation

OmadaWeb.PS PowerShell module

PSGallery Version PSGallery Downloads PowerShell PowerShell PSGallery Platform

DESCRIPTION

OmadaWeb.PS is a PowerShell module containing commands to manage data via Omada web and OData endpoints in the cloud or on-prem. It serves two scenarios equally:

  • Unattended automation - scheduled tasks, CI pipelines and servers with no desktop session, using OAuth2 client credentials with a certificate or a client secret. No browser, no interaction, nothing to type. See Unattended automation.
  • Interactive use - a browser window opens on your Omada instance and you sign in there, at whichever identity provider your tenant uses, multi-factor authentication included.

This module contains two functions that wrap over the built-in PowerShell commands Invoke-RestMethod and Invoke-WebRequest. It adds authentication handling to be used with Omada. A third command, Clear-OmadaWebCache, reports and removes everything the module stores on the machine.

When using browser based authentication this module is able to sign-in automatically to Entra ID when providing credentials via the -Credential parameter. When using number based MFA it is also capable to copy the required number to you clipboard if you have PhoneLink active. It makes it a little bit easier to past the number directly in the Authenticator app on your phone.

COMMANDS

Command Description
Clear-OmadaWebCache Reports and removes the data OmadaWeb.PS stores on this machine.
Export-OmadaSession Captures an authenticated Omada session so another runspace can reuse it.
Import-OmadaSession Seeds this runspace with a session captured by Export-OmadaSession.
Invoke-OmadaRestMethod Sends a request to an Omada REST or OData endpoint and returns the response as objects.
Invoke-OmadaWebRequest Sends a request to an Omada web endpoint and returns the raw HTTP response.

Every command documents itself, so Get-Help works as you would expect:

Get-Help Invoke-OmadaRestMethod -Full
Get-Help Invoke-OmadaRestMethod -Examples

INSTALLATION

To install the module from the PowerShell Gallery, you can use the following command:

Install-Module -Name OmadaWeb.PS

UPDATE

To update the module from the PowerShell Gallery, you can use the following command:

Update-Module -Name OmadaWeb.PS

USAGE

Requirements

This module requires:

  • Windows operating system (x86 or x64 architecture);
  • Windows PowerShell 5.1 or higher (PowerShell 7 is preferred);
  • Windows with Edge Chromium installed (Only for -AuthenticationType "Browser" ).

Importing the Module

To import the module, use the following command:

Import-Module OmadaWeb.PS
# Use WebView2 for a request
Invoke-OmadaWebRequest -Uri "https://your-omada-instance.com/api/data"

Authentication Types

# Use Selenium for a request
Invoke-OmadaWebRequest -Uri "https://your-omada-instance.com/api/data" -AuthenticationType "Browser"

Unattended automation (scheduled tasks, CI and servers without a desktop)

A REST wrapper for an identity governance product earns its keep in the jobs nobody watches: the nightly reconciliation, the joiner-mover-leaver feed, the pipeline that asserts a policy still holds. Those run where there is no browser, no desktop session and nobody to approve anything, so -AuthenticationType "OAuth" is not a fallback for that case - it is the case the module was built to serve.

OAuth here means the OAuth2 client credentials grant: the script authenticates as an application, not as a person. The application proves who it is in one of two ways.

Certificate Client secret
Supplied with -ClientId + -OAuthCertificateThumbprint / -OAuthCertificatePath / -OAuthCertificate -Credential (client id as user name, secret as password)
Travels on the wire A short-lived signature. The private key never leaves the machine The secret itself, on every request
If a log or a script leaks Nothing reusable Full access until the secret is rotated
Recommended by Microsoft Yes Only where a certificate is impossible

Use a certificate. The module signs a JSON Web Token with the certificate's private key (RFC 7523) and sends that in place of the secret, which is what Entra ID and every other compliant provider expect.

Setting it up end to end

1. Register the application in Entra ID. In Entra admin center → Applications → App registrations → New registration, register an application for the job. Note its Application (client) ID and Directory (tenant) ID. No redirect URI is needed - this application never signs a user in.

2. Give it a credential.

  • Certificate (recommended). Create one and keep the private key on the machine that runs the job:

    $Certificate = New-SelfSignedCertificate -Subject "CN=OmadaWeb.PS automation" -CertStoreLocation "Cert:\CurrentUser\My" -KeyExportPolicy NonExportable -KeySpec Signature -NotAfter (Get-Date).AddYears(1)
    Export-Certificate -Cert $Certificate -FilePath ".\OmadaWeb.PS-automation.cer" | Out-Null
    $Certificate.Thumbprint

    Upload the exported .cer - the public half only - under Certificates & secrets → Certificates. A certificate issued by your own PKI works the same way and is preferable where you have one.

    For a job that runs as a service account or in a container, export a password-protected .pfx instead and hand it to the command with -OAuthCertificatePath and -OAuthCertificatePassword.

  • Client secret. Under Certificates & secrets → Client secrets. Store it in SecretManagement or another vault, never in the script, and put a rotation date in the calendar.

3. Grant the application access to the Omada API. The token has to be issued for Omada, which means requesting a scope that belongs to the Omada application rather than to your own. In your tenant, find the enterprise application for your Omada instance, and grant your new application the application permission (app role) it exposes; admin consent is required because there is no user to consent. The audience the module requests is <Application ID URI>/.default, where the Application ID URI defaults to the base URL of the request - override it with -EntraApplicationIdUri when Omada is registered under a different URI.

4. Map the application to an Omada account. A valid token gets the request past authentication; what it may then read or write is decided by Omada. Give the service principal an Omada identity or service account with exactly the data objects and operations the job needs, following Omada's documentation for your version - the exact screen differs between Omada Identity Cloud and on-premises. A job that only reads identities should not be able to write them.

5. Run it.

# Certificate from the machine's certificate store, named by thumbprint.
$Identities = Invoke-OmadaRestMethod -Uri "https://example.omada.cloud/odata/dataobjects/identity" -Paged `
    -AuthenticationType "OAuth" `
    -EntraIdTenantId "c1ec94c3-4a7a-4568-9321-79b0a74b8e70" `
    -ClientId "a1b2c3d4-5e6f-7890-abcd-ef1234567890" `
    -OAuthCertificateThumbprint "9A8B7C6D5E4F30211A2B3C4D5E6F708192A3B4C5"
# Certificate from a password-protected .pfx, for a container or a service account.
$CertificatePassword = ConvertTo-SecureString $env:OMADA_PFX_PASSWORD -AsPlainText -Force
$Identities = Invoke-OmadaRestMethod -Uri "https://example.omada.cloud/odata/dataobjects/identity" -Paged `
    -AuthenticationType "OAuth" `
    -EntraIdTenantId "c1ec94c3-4a7a-4568-9321-79b0a74b8e70" `
    -ClientId "a1b2c3d4-5e6f-7890-abcd-ef1234567890" `
    -OAuthCertificatePath "C:\ProgramData\OmadaJobs\automation.pfx" `
    -OAuthCertificatePassword $CertificatePassword
# Certificate fetched from somewhere the module knows nothing about, such as Azure Key Vault.
$Identities = Invoke-OmadaRestMethod -Uri "https://example.omada.cloud/odata/dataobjects/identity" -Paged `
    -AuthenticationType "OAuth" `
    -EntraIdTenantId "c1ec94c3-4a7a-4568-9321-79b0a74b8e70" `
    -ClientId "a1b2c3d4-5e6f-7890-abcd-ef1234567890" `
    -OAuthCertificate $CertificateFromVault
# The client secret flow, unchanged. The client id is the credential's user name.
$ClientCredential = Get-Credential
$Identities = Invoke-OmadaRestMethod -Uri "https://example.omada.cloud/odata/dataobjects/identity" -Paged `
    -AuthenticationType "OAuth" `
    -EntraIdTenantId "c1ec94c3-4a7a-4568-9321-79b0a74b8e70" `
    -Credential $ClientCredential

The certificate is looked up in CurrentUser\My first and then in LocalMachine\My, so a scheduled task under a service account and an interactive session each find their own without being told where to look. Verbose output names the certificate that signed the request - thumbprint, subject, expiry - along with the client id and the token endpoint, which is what diagnosing a refused sign-in needs. What never reaches any stream is the credential itself: not the client secret, not the private key, and not the signed assertion.

-ClientId is required with a certificate and is never derived from -Credential, so a credential the script holds for something else cannot quietly sign an assertion for the wrong application.

Any identity provider, not only Entra ID

-EntraIdTenantId is a shorthand that builds the Microsoft token endpoint for you. Where Omada is federated to something else, name the endpoint and the scope directly and no Entra-named parameter is involved at all:

Invoke-OmadaRestMethod -Uri "https://example.omada.cloud/odata/dataobjects/identity(123456)" `
    -AuthenticationType "OAuth" `
    -OAuthUri "https://example.okta.com/oauth2/default/v1/token" `
    -OAuthScope "omadaIdentityCloud" `
    -ClientId "0oa1b2c3d4e5f6g7h8i9" `
    -OAuthCertificateThumbprint "9A8B7C6D5E4F30211A2B3C4D5E6F708192A3B4C5"

The client assertion follows RFC 7523, so it is accepted by Okta, Ping, Keycloak, ADFS and anything else that implements private_key_jwt. Providers differ in what they call the scope and whether the assertion audience must be the token endpoint or the issuer; the module sends the token endpoint, which is what the specification requires and what these products expect.

What is not here, and why

Device-code flow is deliberately not implemented. It was evaluated for this scenario and does not fit it:

  • It is a delegated flow. The token it returns represents a person, so it does not solve authenticating a job - it only moves where the person has to be. A scheduled task cannot read a code off a console and type it into another device.
  • Its refresh token would have to be persisted to survive between runs, which puts a long-lived, user-scoped credential on disk. That is a worse security position than the certificate this module now supports, for less capability.
  • It requires the application to be registered as a public client, which is the opposite of what an unattended integration should be.
  • The interactive case it would serve is already covered. -AuthenticationType "WebView2" signs in through an embedded browser and caches the session, and on a machine where a browser genuinely cannot run, a certificate needs no human at all.

Replacing interactive browser sign-in with token acquisition was investigated separately in #23 and closed: Omada is itself the OpenID Connect relying party, and the session it hands back is established in the browser. Device code would not change that either.

A token is requested per call. There is no token cache yet, so a script making many calls asks the identity provider for a token each time. That is tracked in #29 and does not affect correctness, only the number of round trips.

Using an existing session, without ever prompting

-AuthenticationType "OAuth" covers the job that authenticates as an application. A different kind of background work still has to run as the signed-in person: a keep-alive ping that stops an idle session expiring, a query dispatched to a worker runspace, a refresh that runs while someone is at the keyboard doing something else.

That work has a hard requirement of its own. It must never put a sign-in window on the screen. A prompt nobody asked for is at best startling and at worst - in a runspace with no interactive desktop - a WebView2RuntimeNotFoundException that takes the job down with it.

-NoInteractiveAuthentication is the switch for exactly that. The request is sent with the existing session cookie, precisely as it would be without the switch, and no code path under it can reach Selenium, WebView2, or any other window. When there is no usable session it says so instead of signing in:

try {
    Invoke-OmadaRestMethod -Uri "https://example.omada.cloud/api/v2/health" -NoInteractiveAuthentication -ErrorAction Stop
    "Session is still alive" | Write-Verbose
}
catch [System.Security.Authentication.AuthenticationException] {
    # No session, or the server rejected the one we had. Stop the watchdog and leave signing in to
    # whatever the user does next - do not try to acquire a session behind their back.
    "Omada session is gone; stopping the keep-alive." | Write-Warning
}

The error is distinguishable on purpose, because telling session still good from session gone cheaply is the whole point:

FullyQualifiedErrorId starts with OmadaSessionExpired
Exception System.Security.Authentication.AuthenticationException
Raised when no cookie is cached for this tenant, or the server answers HTTP 401
Side effect the rejected session is dropped, so the next call without the switch signs in normally

Match the error id with a wildcard ($_.FullyQualifiedErrorId -like "OmadaSessionExpired*"), or catch the exception type as above. PowerShell appends the name of each function an error passes through to the id, so it is a prefix rather than the whole string.

Two things worth knowing:

  • The switch changes behaviour only for -AuthenticationType "Browser" and -AuthenticationType "WebView2", the two types that can sign a user in. It is accepted with every other type, where it is already true, so a wrapper can pass it unconditionally.
  • It cannot be combined with -ForceAuthentication, which exists to discard the session and sign in again. The combination is refused rather than silently resolved one way or the other.

A session still has to be established once, interactively, before any of this works - the switch uses a session, it never creates one.

Reusing a session in another runspace

The switch above stops a worker prompting. It does not give the worker a session to use, and by itself a worker has none: authentication state belongs to one module instance, and a background runspace imports its own. It starts with an empty session table even though the application that created it signed in seconds earlier.

Export-OmadaSession and Import-OmadaSession are the supported way across that boundary. Capture the session where the sign-in happened, hand the state to the worker, and put it back there:

# On the runspace that signed in.
$State = Export-OmadaSession -Uri "https://example.omada.cloud"

$PowerShell = [powershell]::Create()
$null = $PowerShell.AddScript({
        param($State, $Uri)

        Import-Module OmadaWeb.PS
        Import-OmadaSession -State $State

        # Reuses the session that was signed in elsewhere. No sign-in, no window, no disk.
        Invoke-OmadaRestMethod -Uri $Uri
    }).AddArgument($State).AddArgument("https://example.omada.cloud/api/v2/identity")

$PowerShell.Invoke()

Neither command touches the disk. The session cookie is a live bearer token, so it is never a property of the state object: it is encrypted with DPAPI for the current Windows user account and carried as ciphertext in ProtectedState. Any process already running as that account can decrypt it - including on another computer where the account's DPAPI keys roam through a roaming profile or credential roaming - so treat the state object as a secret. It names neither the account nor the tenant's session key - only a hash that lets you match it to a log line.

The worker's requests behave as they always do, which includes refreshing the encrypted cookie cache under %LOCALAPPDATA%\OmadaWeb.PS - the same DPAPI-protected file any other successful request writes, never a plaintext token. Pass -SkipCookieCache on the worker's calls if you would rather it left no trace on disk at all.

That protection is scoped to the Windows user account that exported the state, not to a computer: any process running as that account can decrypt it, including on another machine where the account's DPAPI keys roam. Anything else - a different user, or a state damaged or altered in transit - is refused as OmadaSessionStateUnreadable rather than quietly ignored.

A seeded session may not sign in. Everything that could open a browser window is refused for it, whether or not the worker's own call remembered -NoInteractiveAuthentication, because a worker runspace usually has no desktop to put a window on and nobody watching it. When the session turns out to be dead - refused on import because its cookie has already expired, or refused later because the server answers HTTP 401 - the worker gets the same catchable error described in the previous section:

try {
    Import-OmadaSession -State $State
    Invoke-OmadaRestMethod -Uri $Uri -ErrorAction Stop
}
catch [System.Security.Authentication.AuthenticationException] {
    # FullyQualifiedErrorId starts with OmadaSessionExpired.
    "The session this worker was handed is gone; asking for a fresh one." | Write-Warning
}

Use Import-OmadaSession -AllowInteractiveAuthentication only where a sign-in window would actually be welcome.

Two things worth knowing:

  • A session is identified by the environment, the authentication type and the account, so Export-OmadaSession has to be given the same -UserName, -Credential or -SessionKey the original request used. Without them it exports the session of the default authentication type and no named account, which may not be the one you meant.
  • Omada session cookies are short lived - roughly ten minutes. Export close to where the state is used rather than holding one; Import-OmadaSession refuses a cookie that has already expired instead of seeding a session that cannot work.

Choosing the account to sign in with

By default the browser decides. It signs in with the account Windows is logged on with, or with whoever used this session last, and for a workstation that belongs to the tenant you are administering that is exactly right - the sign-in is instant and nobody is asked anything.

It is wrong the moment more than one identity is in play. A consultant's own account, a guest account in the customer's tenant, an acceptance account and a production account: the browser picks one silently, and Entra ID answers with a refusal that names neither what it picked nor what it wanted.

AADSTS50178: User account '{EUII Hidden}' from identity provider 'https://sts.windows.net/<tenant id>/'
does not exist in tenant '<tenant> production' and cannot access the application ... in that tenant.

Two parameters take that choice back:

# Sign in as a named account. No password is needed.
Invoke-OmadaRestMethod -Uri "https://example.omada.cloud/api/..." -UserName "mark@example.com"

# Or be shown the account picker, including the option to use an account the browser does not know.
Invoke-OmadaRestMethod -Uri "https://example.omada.cloud/api/..." -SelectAccount

The account is named in the sign-in request, not typed into the page. -UserName is sent to Entra ID as login_hint together with prompt=login, and -SelectAccount as prompt=select_account. That is the whole point: a session for somebody else can no longer answer the request before a page is ever drawn, which is what the refusal above is. Single sign-on with the Windows account is turned off for these sign-ins for the same reason.

Nothing else in the request is touched - state, nonce and the redirect URI stay exactly as Omada built them, and a prompt that Omada sets itself is left alone.

-UserName "mark@example.com" that account signs in
-Credential $Credential the credential's user name is the account; its password is filled in when it has one
-SelectAccount Entra asks which account to use
neither unchanged: the browser decides

The two cannot be combined - Entra ID accepts an account name or an account picker, not both - and -UserName cannot be combined with -Credential, which carries a user name of its own. Both apply to -AuthenticationType "WebView2" (and to "Browser" once it runs on WebView2); supplying them with any other type is refused rather than silently ignored.

A password is optional. -UserName supplies none at all, and a -Credential may carry an empty one:

$Credential = [System.Management.Automation.PSCredential]::new("mark@example.com", [System.Security.SecureString]::new())

The account name is filled in, an empty password is never submitted - that is one of the attempts an account has before Entra ID locks it out - and if Entra offers a passwordless method the module takes it. When it insists on a password anyway, the window stays open and waits for you to type it.

Each account gets its own session, meaning its own cookie cache and its own browser profile, keyed on the account name exactly as -Credential and -SessionKey already are. Two accounts against the same Omada environment therefore no longer need signing out in between, and neither can be silently signed in as the other.

Signing in, and what happens when Microsoft changes the sign-in page

Every browser-based authentication type signs in the same way a person does: a browser window opens on your Omada instance, and you complete the sign-in there. Passing a -Credential for an Entra tenant adds one convenience on top of that - the module recognizes the Microsoft sign-in pages and fills the fields in for you.

That recognition rests on element IDs Microsoft can change at any time, and does. When a page no longer matches what the module knows, the module stops filling fields in and hands the window back to you with a warning such as:

WARNING: Automated Microsoft sign-in could not continue - handing control back to you.
  State            : ProcessingScenarios/NoMatchingScenario
  Missing elements : i0116, idSIButton9
  Elements present : signInName
  Page URL         : https://login.microsoftonline.com/common/oauth2/authorize

A change to the sign-in page degrades autofill, not login. The window is open and the request continues as soon as you have signed in yourself, exactly as it does for every tenant that is not on Entra - there, signing in by hand at your own identity provider is the normal path anyway.

The warning names the state, the elements that were expected but absent, and the page the browser was on. That is what a fix needs, so please include it when reporting the change at GitHub Issues. No query string is printed, since sign-in URLs carry request identifiers.

The module waits 60 seconds without progress before it gives up on autofill, so a slow round trip to Microsoft is not mistaken for a changed page. Waiting for you to approve a sign-in request in your authenticator app does not count against that.

A page that asks for something the command was never given is not a changed page, and is not reported as one. A -Credential that carries a user name but no password is a normal way to use the module: the user name is filled in, an empty password is never submitted, and when Entra insists on a password anyway the module says so and leaves the window open for you.

WARNING: Automated Microsoft sign-in is waiting for you - handing control back to you.
  State            : Deciding/PasswordRequired
  Page URL         : https://login.microsoftonline.com/common/login
  Reason           : The credential has no password and this page offers no way to sign in without one.
Entra ID is asking for something that was not supplied to this command - a password, or a verification code from your device. Please complete the sign-in yourself in the browser window that is open; it stays open and waits for you. Nothing is broken and there is nothing to report.

No selector is named there, and no bug report is asked for, because nothing about the page is broken.

You should not normally be the one to find out. A scheduled job signs in to Entra ID once a day in a real browser and opens an issue when autofill stops recognising a screen, so a change on Microsoft's side is usually already known - and often already fixed - by the time you meet it. See the Entra sign-in canary.

When Omada refuses the sign-in

A sign-in can also fail on the other side of the redirect. Your identity provider authenticates you, hands the browser back to Omada, and Omada decides it cannot let you in - because the account is not a member of the tenant the Omada application is registered in, because the application registration is not accepted, or for any other reason it reports. That failure is not an HTTP error and not a redirect: it is a message rendered on Omada's own logon page, which then simply sits there.

Nothing that a sign-in usually watches for happens next. No authentication cookie is ever set, so the module used to wait out its response watchdog, close the window, open a new one, and land on the same page again - three times over, half an hour, ending in Could not authenticate to '...' with nothing said about why.

The module now reads that page. An error it recognizes as final ends the sign-in immediately, with the message Omada showed:

WARNING: Sign-in was refused and will not be retried.
  Error code : AADSTS50178
  Page URL   : https://example.omada.cloud/logon.aspx
  Engine     : WebView2
  Message    : AADSTS50178: User account '...' from identity provider '...' does not exist in tenant 'Example' and cannot access the application '...' in that tenant. The account needs to be added as an external user in the tenant first.
  Meaning    : The account that signed in is not known in the tenant the Omada application is registered in.
  Account in : tenant be4c52b6-1a23-493e-a8ce-f36325d16462
  Needed in  : tenant 'Example'
  Application: example.com (Omada) (a1880835-5fff-4d48-b926-44471e6f3c6c)
  Correlation: 53b30bf1-f9c9-4ad1-8bba-5442011f3a7c
  Trace      : c5936087-19ec-4f9d-bbfa-9202d9218900
This account cannot be used for this application however often the sign-in is repeated, so no further attempts are made. Sign in with an account of tenant 'Example', or have this account invited into it as a guest, and try again.
Entra ID withholds the account name from this message because it identifies an end user. Look the attempt up by its correlation ID in the sign-in logs of the tenant that refused it to see which account was used.

A refusal about the account gets one more window, with the picker on it. When the sign-in was refused because the account the browser chose is not known in the application's tenant - and only then - the module says so and opens the sign-in window once more with prompt=select_account, so you can pick an account that does exist there:

WARNING: The account the browser signed in with is not known in tenant 'Example productie'. Opening the
sign-in window once more, this time asking which account to use - please choose one that exists in that
tenant.

Once, never twice: a second refusal is the tenant repeating itself. It is also skipped entirely when you named the account yourself with -UserName or -Credential - the picker asks exactly the question you already answered - and when there is no interactive desktop, where a picker would be a window nobody will ever click and the command would hang instead of failing with a message.

The request then fails with that same message rather than with a bare "could not authenticate", so what to do next is in the error itself. Add -ForceAuthentication to the retry so the sign-in starts from a clean browser session.

Everything under Meaning is lifted out of the message Entra wrote, because all of it is something you have to paste into a portal to get any further and none of it was anywhere you could see it. One thing is deliberately missing: the account name. Entra replaces it with {EUII Hidden} in a message it hands to an application, so the sign-in logs of the tenant that refused the sign-in - searched by the correlation ID above - are the only place the account can be identified.

Only errors a retry cannot change stop the sign-in. An error you can correct in the window that is open - a wrong password on Omada's own logon form - is reported once and otherwise left alone, and so is one the identity provider may recover from by itself, such as server_error or temporarily_unavailable. An error whose wording the module does not recognize is treated as final only when the page offers no way to sign in again, which is what a failed federated sign-in looks like whatever the Omada version calls it.

This applies to both browser engines, and the message is redacted and stripped of its query string like every other diagnostic the module prints.

Deprecations

The module carries its own deprecation schedule and warns you at runtime, once per PowerShell session, when a feature you are using is on it. Nothing switches over silently on a date - each change lands in the first release published after the date below, not on the date itself.

Phase 1 - the Selenium browser engine

Deprecated The Selenium/EdgeDriver engine currently behind -AuthenticationType Browser
Announced 19 August 2026
Replacement WebView2 - which Browser will itself run on after the switch
Supported until 1 March 2027
New features WebView2 only, effective immediately

Until 1 March 2027 the Selenium engine keeps working and keeps receiving bug fixes. It receives no new capability - all new work lands in WebView2.

Windows PowerShell 5.1 support is not affected. It remains fully supported; only the Selenium engine is going away.

What you need to do

If you use -AuthenticationType Browser: nothing, ever. Browser is the long-term correct value. Today it runs Selenium; after the switch the same value runs WebView2.

If you would like WebView2 sooner, simply omit the parameter - WebView2 is today's default:

Invoke-OmadaRestMethod -Uri $Uri                    # WebView2 today, and after the switch too

Important

Do not migrate Browser -> WebView2 to get ahead of this deprecation. WebView2 is itself deprecated (phase 2, see below), so that migration would have to be undone. If you want to name the value explicitly, Browser is the one to write.

Where this is heading

One browser-based login, named for what it does rather than which engine does it:

Invoke-OmadaRestMethod -Uri $Uri -AuthenticationType Browser   # browser login, runs on WebView2
Today First release after 1 Mar 2027 First release after 1 Sep 2027
Default -AuthenticationType WebView2 Browser Browser
Browser runs on Selenium WebView2 WebView2
WebView2 runs on WebView2 WebView2 (deprecated) - removed
-UseWebView2 redundant, warns redundant, warns - removed

Phase 1 (the Selenium engine) is tracked in #50; phase 2 (WebView2 and -UseWebView2) in #51. Nothing in phase 2 breaks before 1 September 2027.

If your environment depends on the Selenium engine and WebView2 is not a viable replacement for you, say so in #50. The timeline can be reconsidered on evidence; it cannot be reconsidered on silence.

Local data footprint

Everything the module stores lives under one root: %LOCALAPPDATA%\OmadaWeb.PS. This is what ends up there, and why:

Artefact Path Contents Protection Lifetime
Encrypted cookie cache %LOCALAPPDATA%\OmadaWeb.PS\Cookies\<session hash> The Omada session cookie, so a later command does not have to sign in again Encrypted with DPAPI, readable only by the current Windows user account - on this machine or any other where that account's DPAPI keys roam Until the cookie is rejected, -ForceAuthentication or -SkipCookieCache is used, or you run Clear-OmadaWebCache
Custom cookie file The folder you pass to -CookiePath The same session cookie Encrypted with DPAPI, readable only by the current Windows user account - the same protection as the cache above Until you delete it. It is not touched by Clear-OmadaWebCache, because the module does not know where you put it
WebView2 browser profiles %LOCALAPPDATA%\OmadaWeb.PS\Edge User Data\OmadaWebView2Profile_<session hash> A dedicated Edge user profile per session, holding the Entra ID cookies and tokens that make re-authentication silent File system permissions of your Windows user profile Until you run Clear-OmadaWebCache
Selenium browser profiles %LOCALAPPDATA%\OmadaWeb.PS\Profiles\<Edge profile>_<session hash> The Edge user-data-dir used when -EdgeProfile is combined with -AuthenticationType Browser File system permissions of your Windows user profile Until you run Clear-OmadaWebCache
Bundled WebView2 assemblies lib\<edition>\<architecture> inside the installed module The Microsoft WebView2 assemblies, fetched and verified against their pinned SHA-256 when the module was built (see SECURITY.md) File system permissions of the module's install location, usually read-only For the lifetime of the installed module version; never written to at runtime
Downloaded binaries %LOCALAPPDATA%\OmadaWeb.PS\Bin Selenium, msedgedriver.exe and their dependencies - plus WebView2 when the module was installed without its bundle - downloaded on first use (see SECURITY.md for the full inventory) File system permissions of your Windows user profile Until you run Clear-OmadaWebCache; re-downloaded when needed
In-memory sessions Not written to disk Session cookies, base URLs and browser profile paths for the current PowerShell session Process memory Until the PowerShell session ends or you run Clear-OmadaWebCache

Note

Up to and including the previous release the encrypted cookie cache was written directly into %TEMP%, one file per session. Any cache found there is moved to %LOCALAPPDATA%\OmadaWeb.PS\Cookies the first time that same session is used again. Caches for sessions you never use again would otherwise stay in %TEMP% indefinitely, so Clear-OmadaWebCache reports them as a separate artefact and removes them. It identifies them by content as well as by name, and removes only those files - never the %TEMP% folder itself, and never files it did not write.

Nothing is sent anywhere except to the Omada instance and identity provider you address, and to the download locations of the components listed above.

Clearing cached data

Clear-OmadaWebCache reports and removes everything in the table above.

# See what is stored, without removing anything
Clear-OmadaWebCache -ListOnly | Format-Table Scope, Artefact, Path, ItemCount, SizeBytes

# See what would be removed
Clear-OmadaWebCache -WhatIf

# Sign out everywhere: drop cookies and browser profiles, keep the downloaded binaries
Clear-OmadaWebCache -Scope Cookies, BrowserProfiles

# Remove everything without being prompted
Clear-OmadaWebCache -Force

-Scope accepts All (the default), Cookies, BrowserProfiles, Binaries and Sessions. Binaries that are already loaded into the running PowerShell session are locked by Windows; the command reports which ones it could not remove, and they can be removed after closing that session.

SYNTAX

Clear-OmadaWebCache (__AllParameterSets)

Clear-OmadaWebCache [-Scope {All | Cookies | BrowserProfiles | Binaries | Sessions}] [-ListOnly <switch>] [-Force <switch>] [-WhatIf <switch>] [-Confirm <switch>] [<CommonParameters>]

Export-OmadaSession (__AllParameterSets)

Export-OmadaSession -Uri <uri> [-AuthenticationType {OAuth | Integrated | Basic | Browser | WebView2 | Windows | None}] [-UserName <string>] [-Credential <pscredential>] [-SessionKey <string>] [<CommonParameters>]

Import-OmadaSession (__AllParameterSets)

Import-OmadaSession -State <object> [-AllowInteractiveAuthentication <switch>] [-PassThru <switch>] [<CommonParameters>]

Invoke-OmadaRestMethod (StandardMethod)

Invoke-OmadaRestMethod -Uri <uri> [-AuthenticationType {OAuth | Integrated | Basic | Browser | WebView2 | Windows | None}] [-EntraIdTenantId <string>] [-EntraApplicationIdUri <string>] [-OAuthScope <string>] [-OAuthUri <string>] [-CookiePath <string>] [-SkipCookieCache <switch>] [-ForceAuthentication <switch>] [-NoInteractiveAuthentication <switch>] [-EdgeProfile <string>] [-InPrivate <switch>] [-UseWebView2 <switch>] [-DebugWebView2 <switch>] [-Paged <switch>] [-MaximumRetryCount <int>] [-RetryIntervalSec <int>] [-ClientId <string>] [-OAuthCertificate <x509certificate2>] [-OAuthCertificatePassword <securestring>] [-OAuthCertificatePath <string>] [-OAuthCertificateThumbprint <string>] [-PreferredMfaMethod {PhoneAppNotification | PhoneAppOTP | OneWaySMS | TwoWayVoiceMobile | TwoWayVoiceAlternateMobile | TwoWayVoiceOffice | ConsolidatedTelephony}] [-SelectAccount <switch>] [-SessionKey <string>] [-SkipBodyRedaction <switch>] [-UserName <string>] [<Invoke-RestMethod Parameters>]

Invoke-OmadaRestMethod (StandardMethodNoProxy)

Invoke-OmadaRestMethod -Uri <uri> -NoProxy [-AuthenticationType {OAuth | Integrated | Basic | Browser | WebView2 | Windows | None}] [-EntraIdTenantId <string>] [-EntraApplicationIdUri <string>] [-OAuthScope <string>] [-OAuthUri <string>] [-CookiePath <string>] [-SkipCookieCache <switch>] [-ForceAuthentication <switch>] [-NoInteractiveAuthentication <switch>] [-EdgeProfile <string>] [-InPrivate <switch>] [-UseWebView2 <switch>] [-DebugWebView2 <switch>] [-Paged <switch>] [-MaximumRetryCount <int>] [-RetryIntervalSec <int>] [-ClientId <string>] [-OAuthCertificate <x509certificate2>] [-OAuthCertificatePassword <securestring>] [-OAuthCertificatePath <string>] [-OAuthCertificateThumbprint <string>] [-PreferredMfaMethod {PhoneAppNotification | PhoneAppOTP | OneWaySMS | TwoWayVoiceMobile | TwoWayVoiceAlternateMobile | TwoWayVoiceOffice | ConsolidatedTelephony}] [-SelectAccount <switch>] [-SessionKey <string>] [-SkipBodyRedaction <switch>] [-UserName <string>] [<Invoke-RestMethod Parameters>]

Invoke-OmadaRestMethod (CustomMethod)

Invoke-OmadaRestMethod -Uri <uri> -CustomMethod <string> [-AuthenticationType {OAuth | Integrated | Basic | Browser | WebView2 | Windows | None}] [-EntraIdTenantId <string>] [-EntraApplicationIdUri <string>] [-OAuthScope <string>] [-OAuthUri <string>] [-CookiePath <string>] [-SkipCookieCache <switch>] [-ForceAuthentication <switch>] [-NoInteractiveAuthentication <switch>] [-EdgeProfile <string>] [-InPrivate <switch>] [-UseWebView2 <switch>] [-DebugWebView2 <switch>] [-Paged <switch>] [-MaximumRetryCount <int>] [-RetryIntervalSec <int>] [-ClientId <string>] [-OAuthCertificate <x509certificate2>] [-OAuthCertificatePassword <securestring>] [-OAuthCertificatePath <string>] [-OAuthCertificateThumbprint <string>] [-PreferredMfaMethod {PhoneAppNotification | PhoneAppOTP | OneWaySMS | TwoWayVoiceMobile | TwoWayVoiceAlternateMobile | TwoWayVoiceOffice | ConsolidatedTelephony}] [-SelectAccount <switch>] [-SessionKey <string>] [-SkipBodyRedaction <switch>] [-UserName <string>] [<Invoke-RestMethod Parameters>]

Invoke-OmadaRestMethod (CustomMethodNoProxy)

Invoke-OmadaRestMethod -Uri <uri> -CustomMethod <string> -NoProxy [-AuthenticationType {OAuth | Integrated | Basic | Browser | WebView2 | Windows | None}] [-EntraIdTenantId <string>] [-EntraApplicationIdUri <string>] [-OAuthScope <string>] [-OAuthUri <string>] [-CookiePath <string>] [-SkipCookieCache <switch>] [-ForceAuthentication <switch>] [-NoInteractiveAuthentication <switch>] [-EdgeProfile <string>] [-InPrivate <switch>] [-UseWebView2 <switch>] [-DebugWebView2 <switch>] [-Paged <switch>] [-MaximumRetryCount <int>] [-RetryIntervalSec <int>] [-ClientId <string>] [-OAuthCertificate <x509certificate2>] [-OAuthCertificatePassword <securestring>] [-OAuthCertificatePath <string>] [-OAuthCertificateThumbprint <string>] [-PreferredMfaMethod {PhoneAppNotification | PhoneAppOTP | OneWaySMS | TwoWayVoiceMobile | TwoWayVoiceAlternateMobile | TwoWayVoiceOffice | ConsolidatedTelephony}] [-SelectAccount <switch>] [-SessionKey <string>] [-SkipBodyRedaction <switch>] [-UserName <string>] [<Invoke-RestMethod Parameters>]

Invoke-OmadaWebRequest (StandardMethod)

Invoke-OmadaWebRequest -Uri <uri> [-AuthenticationType {OAuth | Integrated | Basic | Browser | WebView2 | Windows | None}] [-EntraIdTenantId <string>] [-EntraApplicationIdUri <string>] [-OAuthScope <string>] [-OAuthUri <string>] [-CookiePath <string>] [-SkipCookieCache <switch>] [-ForceAuthentication <switch>] [-NoInteractiveAuthentication <switch>] [-EdgeProfile <string>] [-InPrivate <switch>] [-UseWebView2 <switch>] [-DebugWebView2 <switch>] [-MaximumRetryCount <int>] [-RetryIntervalSec <int>] [-ClientId <string>] [-OAuthCertificate <x509certificate2>] [-OAuthCertificatePassword <securestring>] [-OAuthCertificatePath <string>] [-OAuthCertificateThumbprint <string>] [-PreferredMfaMethod {PhoneAppNotification | PhoneAppOTP | OneWaySMS | TwoWayVoiceMobile | TwoWayVoiceAlternateMobile | TwoWayVoiceOffice | ConsolidatedTelephony}] [-SelectAccount <switch>] [-SessionKey <string>] [-SkipBodyRedaction <switch>] [-UserName <string>] [<Invoke-WebRequest Parameters>]

Invoke-OmadaWebRequest (StandardMethodNoProxy)

Invoke-OmadaWebRequest -Uri <uri> -NoProxy [-AuthenticationType {OAuth | Integrated | Basic | Browser | WebView2 | Windows | None}] [-EntraIdTenantId <string>] [-EntraApplicationIdUri <string>] [-OAuthScope <string>] [-OAuthUri <string>] [-CookiePath <string>] [-SkipCookieCache <switch>] [-ForceAuthentication <switch>] [-NoInteractiveAuthentication <switch>] [-EdgeProfile <string>] [-InPrivate <switch>] [-UseWebView2 <switch>] [-DebugWebView2 <switch>] [-MaximumRetryCount <int>] [-RetryIntervalSec <int>] [-ClientId <string>] [-OAuthCertificate <x509certificate2>] [-OAuthCertificatePassword <securestring>] [-OAuthCertificatePath <string>] [-OAuthCertificateThumbprint <string>] [-PreferredMfaMethod {PhoneAppNotification | PhoneAppOTP | OneWaySMS | TwoWayVoiceMobile | TwoWayVoiceAlternateMobile | TwoWayVoiceOffice | ConsolidatedTelephony}] [-SelectAccount <switch>] [-SessionKey <string>] [-SkipBodyRedaction <switch>] [-UserName <string>] [<Invoke-WebRequest Parameters>]

Invoke-OmadaWebRequest (CustomMethod)

Invoke-OmadaWebRequest -Uri <uri> -CustomMethod <string> [-AuthenticationType {OAuth | Integrated | Basic | Browser | WebView2 | Windows | None}] [-EntraIdTenantId <string>] [-EntraApplicationIdUri <string>] [-OAuthScope <string>] [-OAuthUri <string>] [-CookiePath <string>] [-SkipCookieCache <switch>] [-ForceAuthentication <switch>] [-NoInteractiveAuthentication <switch>] [-EdgeProfile <string>] [-InPrivate <switch>] [-UseWebView2 <switch>] [-DebugWebView2 <switch>] [-MaximumRetryCount <int>] [-RetryIntervalSec <int>] [-ClientId <string>] [-OAuthCertificate <x509certificate2>] [-OAuthCertificatePassword <securestring>] [-OAuthCertificatePath <string>] [-OAuthCertificateThumbprint <string>] [-PreferredMfaMethod {PhoneAppNotification | PhoneAppOTP | OneWaySMS | TwoWayVoiceMobile | TwoWayVoiceAlternateMobile | TwoWayVoiceOffice | ConsolidatedTelephony}] [-SelectAccount <switch>] [-SessionKey <string>] [-SkipBodyRedaction <switch>] [-UserName <string>] [<Invoke-WebRequest Parameters>]

Invoke-OmadaWebRequest (CustomMethodNoProxy)

Invoke-OmadaWebRequest -Uri <uri> -CustomMethod <string> -NoProxy [-AuthenticationType {OAuth | Integrated | Basic | Browser | WebView2 | Windows | None}] [-EntraIdTenantId <string>] [-EntraApplicationIdUri <string>] [-OAuthScope <string>] [-OAuthUri <string>] [-CookiePath <string>] [-SkipCookieCache <switch>] [-ForceAuthentication <switch>] [-NoInteractiveAuthentication <switch>] [-EdgeProfile <string>] [-InPrivate <switch>] [-UseWebView2 <switch>] [-DebugWebView2 <switch>] [-MaximumRetryCount <int>] [-RetryIntervalSec <int>] [-ClientId <string>] [-OAuthCertificate <x509certificate2>] [-OAuthCertificatePassword <securestring>] [-OAuthCertificatePath <string>] [-OAuthCertificateThumbprint <string>] [-PreferredMfaMethod {PhoneAppNotification | PhoneAppOTP | OneWaySMS | TwoWayVoiceMobile | TwoWayVoiceAlternateMobile | TwoWayVoiceOffice | ConsolidatedTelephony}] [-SelectAccount <switch>] [-SessionKey <string>] [-SkipBodyRedaction <switch>] [-UserName <string>] [<Invoke-WebRequest Parameters>]

EXAMPLES

Clear-OmadaWebCache

OmadaWeb.PS keeps state between commands so you do not have to sign in again for every call. All of it lives under %LOCALAPPDATA%\OmadaWeb.PS:

  • Cookies: the Omada session cookie of each session, encrypted with DPAPI for the current user. Caches left in %TEMP% by an earlier version of the module are reported as one extra artefact and removed file by file; the %TEMP% folder itself is never touched, and files there that were not written by this module are left alone.
  • BrowserProfiles: the per-session Edge user profiles used by WebView2 and by Selenium. These hold the Entra ID cookies and tokens that make re-authentication silent, so they are the artefacts to remove when you want to sign out completely or switch user.
  • Binaries: Selenium, WebView2, msedgedriver.exe and their dependencies, downloaded on first use. Removing them only costs a fresh download next time.
  • Sessions: the authentication state held in memory by the current PowerShell session.

Run with -ListOnly to see what is stored without changing anything. Without -ListOnly the artefacts are removed, after confirmation; use -WhatIf to preview and -Force to skip the prompt.

In both cases one object per artefact is returned, reporting the path, how many items it holds, how large it is, how it is protected and whether it was removed.

A binary that is already loaded into the running PowerShell session is locked by Windows and cannot be removed. The command reports which ones it could not remove and continues; close that PowerShell session and run it again to remove them.

Files written by -CookiePath are not touched, because their location is chosen by the caller and is not known to the module. Remove those yourself.

Example 1

Clear-OmadaWebCache -ListOnly | Format-Table Scope, Artefact, Path, ItemCount, SizeBytes

Shows everything the module has stored on this machine without removing any of it.

Example 2

Clear-OmadaWebCache -WhatIf

Reports exactly what would be removed, and removes nothing.

Example 3

Clear-OmadaWebCache -Scope Cookies, BrowserProfiles

Signs out everywhere by dropping the cached session cookies and the Edge profiles holding the Entra ID tokens, while keeping the downloaded binaries so the next command does not have to download them again. Asks for confirmation first.

Example 4

Clear-OmadaWebCache -Force

Removes everything the module stores, without prompting. Useful when handing a machine over, or as a cleanup step at the end of an automated run.

Export-OmadaSession

Returns the session this PowerShell session already signed in with, as one opaque object that can be handed to a background runspace and replayed there with Import-OmadaSession. The worker then makes its requests against the same session, without signing in and without a browser window ever opening.

This exists because authentication state is per module instance. A background runspace imports its own copy of OmadaWeb.PS, so it starts with no session at all and would try to sign in interactively even though the calling application authenticated seconds earlier.

This command writes nothing to disk, and neither does Import-OmadaSession. The session cookie is a live bearer token, so it never appears in the returned object: it is encrypted with DPAPI for the current Windows user account and carried in the ProtectedState property as ciphertext. The object can therefore be passed through a job argument, a queue or a variable without leaking the token to a reader who is signed in as someone else. That protection is scoped to the account, not the computer: any process already running as that user - on this machine, or on another one where the account's DPAPI keys roam through a roaming profile or credential roaming - can decrypt it. It does not stop someone who runs as the account that exported it, so treat the returned object as a secret, the same as the cookie it carries.

The command reads the session that is already there. It never creates one, and it never signs in: when there is no authenticated session for the arguments given, it says so and stops. The arguments are the same ones that identified the session when it was created - the Omada URL, the authentication type, and whichever of -UserName, -Credential or -SessionKey the original call used - because sessions are keyed by all three.

Omada session cookies are short lived. Export the session close to where it is used rather than holding one for a long time, and expect Import-OmadaSession to refuse one whose cookie has already expired.

Example 1

$State = Export-OmadaSession -Uri "https://example.omada.cloud"

Captures the session of the default authentication type, ready to be handed to a worker.

Example 2

$State = Export-OmadaSession -Uri "https://example.omada.cloud" -UserName "someone@example.com"

Captures the session belonging to one specific account, on an environment where more than one account is signed in. The account has to be named the same way the original request named it, because that is part of what identifies the session.

Example 3

$PowerShell = [PowerShell]::Create()
$null = $PowerShell.AddScript({
        param($State, $Uri)
        Import-Module OmadaWeb.PS
        Import-OmadaSession -State $State
        Invoke-OmadaRestMethod -Uri $Uri
    }).AddArgument((Export-OmadaSession -Uri "https://example.omada.cloud")).AddArgument("https://example.omada.cloud/api/v2/identity")
$PowerShell.Invoke()

Runs a request on a background runspace against the session this session signed in with. The worker never signs in: no browser window can open, and nothing is written to disk.

Import-OmadaSession

Takes the state object Export-OmadaSession produced in the runspace that signed in, and installs it here. The next Invoke-OmadaRestMethod or Invoke-OmadaWebRequest made against the same environment, with the same authentication type and the same account or session key, reuses that session instead of authenticating.

Nothing is read from or written to disk, and no request is made: this only puts the session in place.

A seeded session may not sign in. Everything that could open a browser window is refused for it, whether or not the call asked for -NoInteractiveAuthentication, because a worker runspace usually has no desktop to put a window on and nobody watching it. When the session turns out to be dead - refused here because its cookie has already expired, or refused later because the server answers HTTP 401 - the caller gets a terminating error it can catch: an AuthenticationException whose FullyQualifiedErrorId starts with OmadaSessionExpired. The third example below shows the shape. Use -AllowInteractiveAuthentication only where a sign-in window would actually be welcome.

The state is protected with DPAPI for the Windows user account that exported it: any process already running as that account can decrypt it, whether it runs on this machine or on another one where the account's DPAPI keys roam through a roaming profile or credential roaming. It does not stop another process running as that same account, so an exported state is a secret and should be handled like one. A state that cannot be read at all - because it belongs to a different user, or was damaged or altered in transit - is refused as one error rather than silently ignored.

The protected contents are also the authority on which environment the session belongs to, and on when it expires. The BaseUrl and ExpiresOn properties beside them are a convenience for the caller and sit outside the protection, so if either disagrees with what is inside - by accident or by an edit - the state is not trusted on that point: BaseUrl is refused outright, and expiry is decided from the protected copy rather than the visible one, so editing the visible ExpiresOn cannot make an already-dead session look current.

Example 1

Import-OmadaSession -State $State

Seeds this runspace with the session captured elsewhere. The next request against that environment reuses it, and cannot open a sign-in window.

Example 2

$State | Import-OmadaSession -PassThru

Seeds the session and reports what was seeded, which is useful in a worker whose output is the only place its state can be observed from.

Example 3

try {
    Import-OmadaSession -State $State
}
catch [System.Security.Authentication.AuthenticationException] {
    "The exported session has already expired; asking the caller for a fresh one." | Write-Warning
}

Distinguishes a session that is still good from one that is already dead, without making a request and without any chance of a prompt.

Invoke-OmadaRestMethod

Invoke-OmadaRestMethod wraps the built-in Invoke-RestMethod and adds the authentication Omada Identity Cloud and on-premises installations need. Every parameter of Invoke-RestMethod is accepted unchanged, so an existing call can be switched over by changing the command name.

Authentication is selected with -AuthenticationType. The default, WebView2, signs in with an embedded Microsoft Edge browser and works for interactive use, at whichever identity provider your Omada tenant uses, multi-factor authentication included. OAuth authenticates as an application with the client-credentials grant and needs no browser, no desktop session and no interaction at all, which is what unattended scripts, scheduled tasks and CI pipelines should use - with a certificate (-ClientId together with one of the -OAuthCertificate* parameters) in preference to a client secret. Browser, Windows, Integrated and Basic cover Selenium-driven sign-in and the classic on-premises authentication schemes.

After a successful interactive sign-in the session cookie is cached, encrypted with DPAPI for the current user, so subsequent commands in the same or a later PowerShell session do not prompt again. Use Clear-OmadaWebCache to remove it, or -SkipCookieCache to never write it. Sessions are kept apart by base URL, authentication type and, when known, user, so several Omada environments can be addressed from the same PowerShell session.

For OData feeds that return results one page at a time, -Paged follows every @odata.nextLink and returns the complete result set as a single object.

The command name Invoke-OmadaODataMethod is an alias for this command.

Example 1

Invoke-OmadaRestMethod -Uri "https://example.omada.cloud/odata/dataobjects/identity(123456)"

Retrieves one identity from the OData endpoint. Because no -AuthenticationType is given, an embedded Edge browser opens for sign-in the first time; later commands reuse the cached session cookie.

Example 2

Invoke-OmadaRestMethod -Uri "https://example.omada.cloud/odata/dataobjects/identity" -Paged

Retrieves every identity from a paged OData feed. Without -Paged only the first page is returned, together with an @odata.nextLink property.

Example 3

$ClientCredential = Get-Credential
$Identities = Invoke-OmadaRestMethod -Uri "https://example.omada.cloud/odata/dataobjects/identity" -Paged -AuthenticationType "OAuth" -EntraIdTenantId "c1ec94c3-4a7a-4568-9321-79b0a74b8e70" -Credential $ClientCredential

Extracts all identities without any interaction, authenticating to Entra ID with a client id and secret.

Example 4

$Identities = Invoke-OmadaRestMethod -Uri "https://example.omada.cloud/odata/dataobjects/identity" -Paged -AuthenticationType "OAuth" -EntraIdTenantId "c1ec94c3-4a7a-4568-9321-79b0a74b8e70" -ClientId "a1b2c3d4-5e6f-7890-abcd-ef1234567890" -OAuthCertificateThumbprint "9A8B7C6D5E4F30211A2B3C4D5E6F708192A3B4C5"

The same unattended extraction, authenticating with a certificate from the Windows certificate store instead of a client secret. The private key never leaves the machine, so nothing reusable travels on the wire. This is the form to use in scheduled tasks, CI pipelines and on servers without a desktop session. The certificate is looked for in CurrentUser\My and then in LocalMachine\My.

Example 5

$CertificatePassword = ConvertTo-SecureString $env:OMADA_PFX_PASSWORD -AsPlainText -Force
Invoke-OmadaRestMethod -Uri "https://example.omada.cloud/odata/dataobjects/identity(123456)" -AuthenticationType "OAuth" -EntraIdTenantId "c1ec94c3-4a7a-4568-9321-79b0a74b8e70" -ClientId "a1b2c3d4-5e6f-7890-abcd-ef1234567890" -OAuthCertificatePath "C:\ProgramData\OmadaJobs\automation.pfx" -OAuthCertificatePassword $CertificatePassword

Authenticates with a certificate held in a password-protected PKCS#12 file, which is what a container or a job running under an account without a certificate store needs.

Example 6

$Body = @{ FIRSTNAME = "Jane"; LASTNAME = "Doe" }
Invoke-OmadaRestMethod -Uri "https://example.omada.cloud/api/DataObject/Identity" -Method "POST" -Body $Body

Creates an object through the Omada API. -Body is accepted as a hashtable and sent as JSON; the Content-Type and Accept headers default to application/json.

Example 7

Invoke-OmadaRestMethod -Uri "https://example.omada.cloud/odata/dataobjects/identity(123456)" -AuthenticationType "Browser"

Signs in through a full Microsoft Edge browser driven by Selenium instead of the embedded WebView2 browser. The matching WebDriver version is installed automatically.

Example 8

Invoke-OmadaRestMethod -Uri "https://example.omada.cloud/odata/dataobjects/identity(123456)" -Credential $UserCredential

Signs in interactively, but hands the sign-in page the account to use and fills in the password, which saves picking the right account when several are signed in. With number matching multi-factor authentication the number is copied to the clipboard, so with Phone Link and clipboard sharing active it can be pasted straight into the Authenticator app.

Example 9

Invoke-OmadaRestMethod -Uri "https://example.omada.cloud/odata/dataobjects/identity(123456)" -AuthenticationType "OAuth" -OAuthUri "https://example.okta.com/oauth2/default/v1/token" -OAuthScope "omadaIdentityCloud" -Credential $ClientCredential

Authenticates against an identity provider other than Entra ID - here Okta - by supplying the token endpoint and scope explicitly.

Example 10

try {
    Invoke-OmadaRestMethod -Uri "https://example.omada.cloud/api/v2/health" -NoInteractiveAuthentication -ErrorAction Stop
}
catch [System.Security.Authentication.AuthenticationException] {
    "Omada session is gone; stopping the keep-alive." | Write-Warning
}

Uses the session that already exists and cannot open a sign-in window, which is what a background keep-alive or a worker runspace needs. A session that has expired raises a distinguishable terminating error - its FullyQualifiedErrorId starts with 'OmadaSessionExpired' - instead of prompting.

Example 11

Invoke-OmadaRestMethod -Uri "https://omada.contoso.local/odata/dataobjects/identity(123456)" -AuthenticationType "Integrated"

Retrieves an identity from an on-premises installation using Windows Integrated Authentication, without opening a browser.

Invoke-OmadaWebRequest

Invoke-OmadaWebRequest wraps the built-in Invoke-WebRequest and adds the authentication Omada Identity Cloud and on-premises installations need. Every parameter of Invoke-WebRequest is accepted unchanged, so an existing call can be switched over by changing the command name.

Use this command when the response itself matters - status code, headers, raw content or a file to download. For REST and OData endpoints that return JSON, Invoke-OmadaRestMethod is usually the better fit because it deserializes the response for you and can page through OData feeds.

Authentication is selected with -AuthenticationType. The default, WebView2, signs in with an embedded Microsoft Edge browser and works for interactive use, at whichever identity provider your Omada tenant uses, multi-factor authentication included. OAuth authenticates as an application with the client-credentials grant and needs no browser, no desktop session and no interaction at all, which is what unattended scripts, scheduled tasks and CI pipelines should use - with a certificate (-ClientId together with one of the -OAuthCertificate* parameters) in preference to a client secret. Browser, Windows, Integrated and Basic cover Selenium-driven sign-in and the classic on-premises authentication schemes.

After a successful interactive sign-in the session cookie is cached, encrypted with DPAPI for the current user, so subsequent commands in the same or a later PowerShell session do not prompt again. Use Clear-OmadaWebCache to remove it, or -SkipCookieCache to never write it. Sessions are kept apart by base URL, authentication type and, when known, user, so several Omada environments can be addressed from the same PowerShell session.

Example 1

Invoke-OmadaWebRequest -Uri "https://example.omada.cloud"

Signs in to the Omada portal through an embedded Edge browser and returns the response. Useful as a first call to confirm that authentication works and to prime the cookie cache.

Example 2

$Response = Invoke-OmadaWebRequest -Uri "https://example.omada.cloud/api/Health"
$Response.StatusCode

Keeps the full response so the status code and headers can be inspected, which Invoke-OmadaRestMethod does not expose.

Example 3

$ClientCredential = Get-Credential
Invoke-OmadaWebRequest -Uri "https://example.omada.cloud/Report/Export?id=42" -OutFile "C:\Temp\report.xlsx" -AuthenticationType "OAuth" -EntraIdTenantId "c1ec94c3-4a7a-4568-9321-79b0a74b8e70" -Credential $ClientCredential

Downloads a report to disk without any interaction, authenticating to Entra ID with a client id and secret.

Example 4

Invoke-OmadaWebRequest -Uri "https://example.omada.cloud/Report/Export?id=42" -OutFile "C:\Temp\report.xlsx" -AuthenticationType "OAuth" -EntraIdTenantId "c1ec94c3-4a7a-4568-9321-79b0a74b8e70" -ClientId "a1b2c3d4-5e6f-7890-abcd-ef1234567890" -OAuthCertificateThumbprint "9A8B7C6D5E4F30211A2B3C4D5E6F708192A3B4C5"

The same download from a scheduled task, authenticating with a certificate from the Windows certificate store rather than a client secret, so no reusable credential travels on the wire or sits in the script.

Example 5

try {
    $Response = Invoke-OmadaWebRequest -Uri "https://example.omada.cloud/api/v2/health" -NoInteractiveAuthentication -ErrorAction Stop
    "Session is alive, Omada answered {0}" -f $Response.StatusCode | Write-Verbose
}
catch [System.Security.Authentication.AuthenticationException] {
    "Omada session is gone; stopping the keep-alive." | Write-Warning
}

Uses the session that already exists and cannot open a sign-in window, which is what a background keep-alive or a worker runspace needs. A session that has expired raises a distinguishable terminating error - its FullyQualifiedErrorId starts with 'OmadaSessionExpired' - instead of prompting.

Example 6

Invoke-OmadaWebRequest -Uri "https://omada.contoso.local/OData/DataObjects" -AuthenticationType "Windows" -Credential $UserCredential

Requests an on-premises endpoint with explicit Windows credentials, negotiating Kerberos or NTLM when the server issues a challenge.

PARAMETERS

Invoke-OmadaRestMethod and Invoke-OmadaWebRequest parameters

These are added on top of the parameters of the wrapped cmdlet and are the same for both commands, unless stated otherwise.

-AuthenticationType

The type of authentication to use for the request. Default is WebView2. The acceptable values for this parameter are:

  • None: No explicit authentication is used.
  • Basic: Requires Credential. The credentials are sent as an RFC 7617 Basic Authentication Authorization: basic header in the format of base64(user:password).
  • Browser: Browser-based interactive sign-in. Today this runs on Selenium, which automatically installs and updates to the desired webdriver version based on the currently installed Microsoft Edge browser. The Selenium engine is deprecated and supported until 1 March 2027; in the first release published after that date, Browser runs on WebView2 instead. Browser itself is not going away, so no script change is needed at any point - do not migrate to WebView2 to get ahead of this, because that value is deprecated as well. See #50.
  • Integrated: Uses Windows Integrated Authentication.
  • OAuth: Non-interactive OAuth2 client-credentials authentication, for unattended scripts, scheduled tasks and CI pipelines - it opens no browser and needs no desktop session. The client authenticates either with a certificate (-ClientId together with -OAuthCertificateThumbprint, -OAuthCertificatePath or -OAuthCertificate, which is what Microsoft recommends over a secret) or with a client id and secret in -Credential. Entra ID is the default token endpoint; any other provider is reached with -OAuthUri and -OAuthScope.
  • WebView2: For environments where Selenium is restricted, you can use the Microsoft WebView2 NuGet package instead. WebView2 does not use the developer tools of the Edge browser and should work when developer options is not allowed. The WebView2 assemblies ship with the module, so no download is needed; a module installed without them falls back to downloading them into %LOCALAPPDATA%\OmadaWeb.PS\Bin on first use. WebView2 uses a dedicated Edge user profile per session (base URL, authentication type and, when known, user), located under %LOCALAPPDATA%\OmadaWeb.PS\Edge User Data.
  • Windows: Requires Credential. Uses Windows authentication with the supplied credentials. The credential is passed to the underlying web request, which automatically negotiates using Kerberos/NTLM (Negotiate) when the server issues a challenge.

Supplying AuthenticationType overrides any Authorization headers supplied to Headers or included in WebSession.

        Type: System.String
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-EntraIdTenantId

The tenant id or name for -AuthenticationType OAuth.

        Type: System.String
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: AzureAdTenantId
        Dynamic: true
        Accept wildcard characters: false

-EntraApplicationIdUri

Enter the application ID URI when the base url does not equal the configured application ID URI in Entra ID. This parameter is used for -AuthenticationType OAuth.

        Type: System.String
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-OAuthScope

OAuth2 scope to be used. Defaults to the form used for Entra ID. This parameter is used for -AuthenticationType OAuth.

        Type: System.String
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-OAuthUri

Provide a custom OAuth2 URI. Defaults to the form used for Entra ID based on the provided EntraIdTenantId. This parameter is used for -AuthenticationType OAuth.

Together with -OAuthScope this is the provider-neutral way to reach any OpenID Connect or OAuth2 token endpoint, so an Omada tenant federated to Okta, Ping, ADFS or Keycloak needs no Entra-named parameter at all.

        Type: System.String
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-CookiePath

The FOLDER to keep a stored Omada authentication cookie in. The module derives the file name itself, one per session, so pass a directory and not a file path. The file is updated when re-authentication is needed, and created after successful authentication if it is not there yet. When this option is used, the default cookie cache is not written - this file takes its place.

The file is encrypted with DPAPI, exactly like the default cookie cache, so it is readable only by the Windows user account that created it - any process running as that account can decrypt it, including on another machine where the account's DPAPI keys roam. There is no option to write it unencrypted. This parameter only applies in combination with parameter -AuthenticationType Browser or -AuthenticationType WebView2.

Important

Because the protection is tied to the Windows user account, not the computer, a cookie file cannot be copied to a different user - but that same account can still decrypt it on another machine where its DPAPI keys roam, so treat it as a secret. A file written unencrypted by an earlier version of this module is ignored rather than read - you simply sign in again, and the file is replaced with an encrypted one.

        Type: System.String
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-SkipCookieCache

Do not cache the encrypted Omada authentication cookie. It will also not be cached when -CookiePath is used. This parameter only applies in combination with parameter -AuthenticationType Browser and -AuthenticationType WebView2.

        Type: System.Management.Automation.SwitchParameter
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-ForceAuthentication

Force authentication to Omada even when the cookie is still valid.

        Type: System.Management.Automation.SwitchParameter
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-NoInteractiveAuthentication

Use the session that already exists, and never sign in. The request is sent with the existing Omada session cookie exactly as it would be without this switch, but no code path under it can open a browser, a WebView2 window or any other prompt.

Use it for work nobody is watching that still has to run as the signed-in user: a session keep-alive ping, a background runspace, a scheduled job that runs while someone is at the keyboard. Without it, a session that expired mid-job puts a sign-in window on the user's screen unannounced, or fails with a WebView2 runtime error where there is no desktop at all.

When there is no usable session - no cookie for this tenant, or the server answers HTTP 401 - the command raises a terminating error instead of signing in. That error is distinguishable, so a caller can tell a session that is still good from one that is gone and act on it: its FullyQualifiedErrorId starts with OmadaSessionExpired, and its exception is a System.Security.Authentication.AuthenticationException. The expired session is dropped from the cache first, so the next call made without this switch signs in normally.

This switch changes behaviour only for -AuthenticationType Browser and -AuthenticationType WebView2, which are the only types that can sign a user in interactively. It is accepted with every other type as well, where it is already true, so a wrapper can pass it unconditionally.

It cannot be combined with -ForceAuthentication, which discards the session precisely in order to sign in again.

        Type: System.Management.Automation.SwitchParameter
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-EdgeProfile

Use the specified Edge profile for the authentication request. The acceptable values for this parameter are based on the available profiles on your system.

Important

Due to the requirements of Selenium, the selected Edge profile needs to be closed when using this parameter.

        Type: System.String
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-InPrivate

Use InPrivate mode for the authentication request.

        Type: System.Management.Automation.SwitchParameter
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-UseWebView2

Use WebView2 instead of Selenium WebDriver for browser-based authentication.

Important

This parameter is deprecated and obsolete. The default is AuthenticationType WebView2, so this parameter is not needed anymore and will be removed in a future release.

        Type: System.Management.Automation.SwitchParameter
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-DebugWebView2

Use this parameter to enable WebView2 browser debugging options like Developer Tools

        Type: System.Management.Automation.SwitchParameter
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-Paged

Use this parameter to retrieve all pages of data from the API. This parameter is only applicable to Omada API endpoints that support pagination. Only supported for HTTP GET requests (the default); combining -Paged with -Method PUT, POST, or PATCH throws a terminating error.

This parameter only applies to Invoke-OmadaRestMethod.

        Type: System.Management.Automation.SwitchParameter
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-MaximumRetryCount

How many times a failed request is retried before the error is raised. Defaults to 3, so a request is attempted 4 times in total. Use -MaximumRetryCount 0 to switch retrying off.

Only requests that can be repeated safely are retried: HTTP GET and HEAD, including the page requests -Paged makes. A POST, PUT, PATCH or DELETE may already have been applied by the server, so it is never repeated automatically. Retries are triggered by the transient conditions a multi-tenant cloud produces - HTTP 429, 502, 503 and 504, and socket-level network failures - and never by an authentication failure, which is handled by re-authenticating instead. A client-side timeout is not retried either, so -TimeoutSec keeps bounding the call.

Between attempts the command waits -RetryIntervalSec, doubling that wait after each attempt and varying it slightly so that several clients backing off at once do not retry in lockstep. When the server answers with a Retry-After header, the delay it asks for is used instead. Every retry is reported on the verbose stream with the status code and the delay.

        Type: System.Int32
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: MaxRetryCount
        Dynamic: true
        Accept wildcard characters: false

-RetryIntervalSec

The wait in seconds before the first retry, doubled for each attempt after that. Defaults to 2. A Retry-After header sent by the server takes precedence over this value. Has no effect when -MaximumRetryCount is 0.

        Type: System.Int32
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-ClientId

The application (client) id of the service principal to authenticate as. This parameter is used for -AuthenticationType OAuth.

It is required whenever one of the -OAuthCertificate* parameters is used. For the client secret flow the client id is taken from the user name of -Credential instead, so -ClientId is not needed there, and supplying it overrides the user name.

With a certificate the client id is never derived from -Credential, even when one is supplied: a credential held for some other purpose would otherwise sign an assertion for the wrong application, and the identity provider's rejection would name neither cause nor cure.

        Type: System.String
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-OAuthCertificate

An already loaded certificate, including its private key, to authenticate the client with instead of a client secret. This parameter is used for -AuthenticationType OAuth in combination with -ClientId.

Use this when the certificate comes from somewhere this module does not know about, such as Azure Key Vault or a SecretManagement vault. To take it from the Windows certificate store or from a file, use -OAuthCertificateThumbprint or -OAuthCertificatePath instead; exactly one of the three may be supplied.

This is not the same parameter as Invoke-RestMethod's -Certificate, which selects a client certificate for the TLS connection. That one is still available and unchanged.

        Type: System.Security.Cryptography.X509Certificates.X509Certificate2
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-OAuthCertificatePassword

The password protecting the file named by -OAuthCertificatePath, as a SecureString. Omit it for a file that is not password protected.

        Type: System.Security.SecureString
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-OAuthCertificatePath

Path to a PKCS#12 (.pfx or .p12) file holding the certificate and private key to authenticate the client with instead of a client secret. This parameter is used for -AuthenticationType OAuth in combination with -ClientId. Supply the file's password with -OAuthCertificatePassword.

        Type: System.String
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-OAuthCertificateThumbprint

The thumbprint of the certificate to authenticate the client with instead of a client secret. This parameter is used for -AuthenticationType OAuth in combination with -ClientId.

The certificate is looked up in CurrentUser\My and then in LocalMachine\My, so a scheduled task running under a service account and an interactive session find their own certificate without being told where it is. It must have a private key the account can read. Separators are ignored, so a thumbprint copied out of the Windows certificate dialog can be pasted in unchanged.

This is not the same parameter as Invoke-RestMethod's -CertificateThumbprint, which selects a client certificate for the TLS connection. That one is still available and unchanged.

        Type: System.String
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-PreferredMfaMethod

The multi-factor authentication method to select when Entra ID asks which way to sign in, and the account has more than one method registered. Without this parameter the most secure method the account offers is chosen automatically, preferring an Authenticator approval over a code that has to be typed, a code over a text message, and a text message over a voice call.

The values are the method identifiers Entra ID itself uses, so they mean the same thing whatever language the sign-in page is served in:

  • PhoneAppNotification: Microsoft Authenticator approval, including number matching.
  • PhoneAppOTP: A verification code from Microsoft Authenticator.
  • OneWaySMS: A code sent by text message.
  • TwoWayVoiceMobile: A call to the registered mobile number.
  • TwoWayVoiceAlternateMobile: A call to the registered alternate mobile number.
  • TwoWayVoiceOffice: A call to the registered office number.
  • ConsolidatedTelephony: The consolidated telephony method.

When the account does not offer the requested method, a warning is written and the most secure method it does offer is used instead, so a preference never fails a sign-in that would otherwise succeed.

Important

This parameter only applies to -AuthenticationType WebView2, and to -AuthenticationType Browser once that runs on WebView2. Supplying it with any other authentication type raises a terminating error.

        Type: System.String
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-SelectAccount

Ask Entra ID which account to sign in with, instead of letting it choose one.

The sign-in request is sent with prompt=select_account, so Entra shows the account picker - every account the browser already knows, and the option to use one it does not. Use it when you do not want to name an account in advance but the automatic choice is wrong, which is what an AADSTS50178 ... does not exist in tenant refusal means.

Single sign-on with the Windows account is turned off for this sign-in, since it is the thing that made the choice being overruled.

Important

This parameter only applies to -AuthenticationType WebView2, and to -AuthenticationType Browser once that runs on WebView2. It cannot be combined with -UserName or with the user name of -Credential: Entra ID accepts an account name or an account picker, not both.

        Type: System.Management.Automation.SwitchParameter
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-SessionKey

Explicitly discriminate the reusable authentication session (cookie, base URL, WebView2/Selenium profile) to use for this call, in addition to the base URL, -AuthenticationType and -Credential (when supplied). Use this to keep multiple concurrent sessions apart when they would otherwise share the same base URL, authentication type and credential - for example two interactive Browser/WebView2 logins to the same tenant before either has a known user identity. Has no effect on which cookie/base URL etc. is used beyond distinguishing sessions from each other; defaults to an empty value, which reproduces prior single-session-per-(base URL, AuthenticationType, Credential) behavior.

        Type: System.String
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-SkipBodyRedaction

Write the request body to the verbose stream as it was sent, instead of as its keys and value shapes. Use this when the body itself is what you are troubleshooting - the query an Omada SQL troubleshooting call sent, for example - and the shape summary does not tell you what went wrong.

This lifts one rule only. Inside the body, a member whose name names a secret is still masked, credentials and secure strings are still masked by type, and a token or authorization header appearing inside a body value is still caught. Everything outside the body - headers, credential, session cookie - is unaffected.

Only use it when the body carries no secret you would mind reading back: the verbose stream is what callers capture into their own logs and export to a file, so anything shown here can end up attached to a support ticket.

        Type: System.Management.Automation.SwitchParameter
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

-UserName

The account to sign in with, as its user principal name. Use it when the browser would otherwise sign in as somebody else - the Windows account you are logged on with, or whoever used this session last - which is what happens when a tenant has more than one identity available and nobody says which one to use.

The name is sent to Entra ID as part of the sign-in request itself (login_hint, with prompt=login), so it decides which account is used before any sign-in screen is drawn. That is the difference between this parameter and typing a name into the window: an existing session for another account can no longer answer the request silently.

No password is needed. When one is supplied, through -Credential, it is filled in as before; when it is not, the account name is filled in and the sign-in waits in the open window for you to complete it - with a passwordless method, or by typing the password yourself.

Each account gets its own session: its own cookie cache and its own browser profile. Signing in to the same environment as two different accounts therefore does not require signing out in between.

Leave it out to keep the current behaviour, where the browser decides which account to use.

Important

This parameter only applies to -AuthenticationType WebView2, and to -AuthenticationType Browser once that runs on WebView2. It cannot be combined with -Credential, which carries a user name of its own, nor with -SelectAccount, because Entra ID accepts an account name or an account picker but not both.

        Type: System.String
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: true
        Accept wildcard characters: false

Clear-OmadaWebCache parameters

-Force

Remove without asking for confirmation. -WhatIf still takes precedence.

        Type: System.Management.Automation.SwitchParameter
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: false
        Accept wildcard characters: false

-ListOnly

Report what is stored without removing anything.

        Type: System.Management.Automation.SwitchParameter
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: false
        Accept wildcard characters: false

-Scope <string[]>

Which artefacts to report and remove: All (the default), Cookies, BrowserProfiles, Binaries or Sessions. More than one value can be given.

        Type: System.String[]
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: false
        Accept wildcard characters: false

Export-OmadaSession parameters

-AuthenticationType

The authentication type the session was established with. Defaults to WebView2, the same default Invoke-OmadaRestMethod and Invoke-OmadaWebRequest use.

        Type: System.String
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: false
        Accept wildcard characters: false

-Credential

The credential the original call used. Only its user name identifies the session; the password is not read and is never part of the exported state.

        Type: System.Management.Automation.PSCredential
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: false
        Accept wildcard characters: false

-SessionKey

The value the original call passed as -SessionKey, when it used one to keep several sessions to the same environment apart.

        Type: System.String
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: false
        Accept wildcard characters: false

-Uri

The Omada URL the session was established against. Only the scheme, host and port are used, so the URL of any request made against that environment will do.

        Type: System.Uri
        Required: true
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: false
        Accept wildcard characters: false

-UserName

The account the session signs in as, when the original call named one with -UserName.

        Type: System.String
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: false
        Accept wildcard characters: false

Import-OmadaSession parameters

-AllowInteractiveAuthentication

Allow this session to sign in interactively after all, if it turns out to be expired. Without it - the default - nothing under the seeded session can open a browser window, and an unusable session raises a terminating error instead.

        Type: System.Management.Automation.SwitchParameter
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: false
        Accept wildcard characters: false

-PassThru

Return a summary of the session that was seeded. Without it the command returns nothing.

        Type: System.Management.Automation.SwitchParameter
        Required: false
        Position: Named
        Accept pipeline input: false
        Parameter set name: (All)
        Aliases: None
        Dynamic: false
        Accept wildcard characters: false

-State

The object returned by Export-OmadaSession. Accepted from the pipeline.

        Type: System.Object
        Required: true
        Position: Named
        Accept pipeline input: true (ByValue)
        Parameter set name: (All)
        Aliases: None
        Dynamic: false
        Accept wildcard characters: false

Invoke-RestMethod Parameters / Invoke-WebRequest Parameters

All other parameters, except the exclusion list below, are inherited from the PowerShell built-in functions Invoke-RestMethod for Invoke-OmadaRestMethod and Invoke-WebRequest for Invoke-OmadaWebRequest.

The following native parameters are excluded because they are handled within the module: -Session, -WebSession, -Authentication, -SessionVariable, -UseDefaultCredentials, -UseBasicParsing.

Please see Microsoft documentation for all other available options.

SECURITY

Found a security problem? Please report it privately through GitHub Security Advisories instead of opening an issue. See SECURITY.md for supported versions, response targets and scope.

The binaries the module downloads on first use are pinned to an exact version and SHA-256 in OmadaWeb.PS/DependencyLock.psd1, which ships with the module. Each download is verified against that hash before it is unpacked or loaded, and anything that does not match is deleted and refused. msedgedriver.exe has to match your installed Edge version so it cannot be pinned; its Authenticode signature is verified instead. See Runtime dependency verification.

The WebView2 assemblies behind the default -AuthenticationType WebView2 are not downloaded at all: they ship inside the module under lib\<edition>\<architecture>, fetched and verified against the same pin when the module was built. That makes the default work on a machine with no access to nuget.org, and keeps the assemblies out of a user-writable directory. A module installed without them still downloads and verifies them exactly as before. See Why the WebView2 assemblies are bundled.

Every release has a CycloneDX Software Bill of Materials (OmadaWeb.PS-<version>.cdx.json) attached as a release asset, covering the module, the assemblies it bundles and the components it downloads at runtime. The inventory it is generated from is Build/Dependencies.psd1.

CONTRIBUTING

Contributions are welcome! If you have ideas for improvements or bug fixes, feel free to open a pull request on GitHub.

Please read CONTRIBUTING.md first — it covers where the tests live, how to run them, how a pull request gets validated, and the one rule we ask every change to follow: every bug fix ships with the test that would have caught it.

The COMMANDS, SYNTAX, EXAMPLES and PARAMETERS sections of this README are generated from the module, so help is written once:

  • Comment-based help in OmadaWeb.PS/Public/*.ps1 is the source of every synopsis, description and example, and of the parameter descriptions of commands that declare their parameters normally. It is the same help Get-Help shows.
  • The -HelpMessage strings in OmadaWeb.PS/Private/Set-DynamicParameter.ps1 are the source of the parameter descriptions of Invoke-OmadaRestMethod and Invoke-OmadaWebRequest, whose parameters are all added at runtime and so cannot carry comment-based .PARAMETER entries. Get-Help reads the same strings.

After changing either, run Build/Update-ReadmeHelp.ps1 (PowerShell 7) to refresh those sections before committing. Do not edit them by hand. Build/Test-CommentBasedHelp.ps1 runs as part of the build and fails when an exported command is missing a synopsis, a description, at least three examples, a link, or help for one of its parameters.

RELATED LINKS

Invoke-RestMethod

Invoke-WebRequest

Omada Documentation

LICENSE

This project is licensed under the MIT License. See the LICENSE file for details.

About

PowerShell module for managing Omada Identity (Cloud) data via web and OData endpoints, supporting OAuth2 and browser-based authentication.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages