How do you change an Ignition user password via script?

Daniel Price6 min read
HMI / SCADAOther ManufacturerTechnical Reference
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Where does a self-service password change have to execute?

It has to execute in gateway scope. A Vision client, especially one with no authenticated session, cannot modify an internal user source. The gateway can. The request path is: Vision client window, then a scripted request to a gateway message handler, then the gateway calls the user management functions against the internal user source, then the response returns to the client.

Two issues stop this from working out of the box:

  • No session before login. Vision project scripts only run once a client session exists. The native login screen does not run project scripts. "Without being logged in" therefore means "logged in as a low-privilege account that can do nothing except request a password change."
  • No password or expiry accessor. The documented accessors on the object returned by system.user.getUser() do not include the password. They also do not list any days-until-expiration value.

The fix has two parts:

  1. Build a gateway message handler that validates the old password and writes the new one.
  2. Find out what the user object actually carries by iterating its property values on an account whose password is set to expire.

Which approaches can carry the request, and which one works?

Approach Runs before real login? Permission needed in client Credential exposure Verdict
Client-scope user edit called directly from the Vision window No: needs an authenticated user with user-management rights High The client session holds edit rights over every user Reject
Administrator resets the password in the gateway web interface n/a None (manual) An admin sees or sets the password Fallback only
Gateway message handler called from a restricted auto-login Vision session Yes None beyond sending the request Credentials travel once over the gateway connection. The edit runs in gateway scope. Recommended

The message handler approach is the only one that meets both requirements: the user needs no prior login, and the old password is checked before anything changes. The gateway performs the edit, so no client session ever holds user-management rights.

How do you build the gateway message handler path?

  1. Create a restricted entry session. In the Vision project, enable auto-login with a dedicated account that has no roles. Make the landing window a custom login screen that offers two actions: log in (system.security.switchUser) and change password.
  2. Check where old-password validation can run. Look up system.security.validateUser in the scripting reference for your gateway version and read its scope line.
    • If gateway scope is listed, validate inside the handler.
    • If only Vision Client is listed, validate in the client before sending the request. In that case, treat the handler as reachable only from the restricted session and log every call.
  3. Add a gateway message handler in the project (Gateway Event Scripts, Message tab). A minimal skeleton:
    def handleMessage(payload):
        source = "default"   # name of your internal user source
        username = payload["username"]
        newPwd = payload["newPassword"]
        # old-password check goes here if validateUser is gateway-scoped
        user = system.user.getUser(source, username)
        if user is None:
            return {"ok": False, "msg": "Unknown user"}
        user.set("password", newPwd)
        resp = system.user.editUser(source, user)
        errs = [str(e) for e in resp.getErrors()]
        return {"ok": len(errs) == 0, "msg": "; ".join(errs)}
  4. Call the handler from the change-password window:
    payload = {"username": u, "oldPassword": oldPwd, "newPassword": newPwd}
    result = system.util.sendRequest("MyProject", "changePassword", payload)
    if not result["ok"]:
        system.gui.errorBox(result["msg"])
  5. Return a structured result and clear the fields. The window should display the handler's message, then clear the password text fields whatever the outcome.

Where is the days-to-expiration value?

No documented accessor exposes it. Reading the raw property set is the reliable way to see what the internal user source stores. Run this in the Script Console, which executes in the Designer rather than the gateway, against a user whose password falls under the gateway's password policy. Then run it again inside a gateway-scoped script to compare the two scopes.

user = system.user.getUser("default", "someUser")
for pv in user:
    print pv.getProperty().getName(), "=", pv.getValue()

Decide from the output:

What the dump shows What to do
A date property tied to the last password change Days remaining = policy expiration interval (from the user source's password policy settings on the gateway) minus system.date.daysBetween(lastChange, system.date.now())
A date property holding the expiry itself Days remaining = system.date.daysBetween(system.date.now(), expiry)
No password-date property at all Record your own timestamp. Have the handler write username and change date to a database table on every successful edit, then compute against the policy interval.

If the property exists, it is undocumented and may change between gateway versions. Keep the read behind one project library function so a rename only breaks one place.

What breaks on this path?

Symptom Cause Check
sendRequest times out or reports that no handler was found Handler name or project name mismatch, or the project has not been saved to the gateway Compare the exact handler string. Save and publish.
Edit returns no errors, but the old password still works Wrong user source name, so the edit went to a different source Print the source name inside the handler and compare it with the gateway user source list
Edit fails with a policy message New password violates the complexity or history rules Show resp.getErrors() to the user unchanged
Anyone can reset anyone's password Handler skips old-password validation Validate in the handler, or strictly in the client, per step 2
Passwords appear in logs Payload logged verbatim for debugging Log the username and outcome only
Nothing works on an IdP-based project This path assumes classic authentication with an internal user source Confirm the project authentication mode

How do you verify the change end to end?

  1. Launch a fresh Vision client. Confirm it lands in the restricted auto-login session and that no protected window opens.
  2. Submit a wrong old password. Confirm the request is rejected and the user record is unchanged.
  3. Submit a new password that violates the policy. Confirm the policy error from editUser reaches the window.
  4. Submit a valid change. Confirm the handler returns ok.
  5. Run the property dump again and confirm the password-date property (or your database timestamp) now shows today's date.
  6. Log in with the new password through system.security.switchUser, then confirm the old password is refused.

FAQ

Why does system.user.getUser not return the password?

The user object deliberately omits the password from its documented accessors. You can set a new value and commit it with system.user.editUser in gateway scope, but you cannot read the stored password back.

Why does a Vision client need auto-login to offer a pre-login password change?

Vision project scripts only run inside a client session, and the native login screen runs none. A restricted auto-login account provides a session in which a custom window can call system.util.sendRequest to the gateway handler.

Why does the days-to-expiration property not show in the Ignition manual?

It is not a documented accessor. Iterate the property values of a user covered by the password policy to see what the internal user source stores. If there is no usable date, have the handler record each change in a database table and compute days remaining from the policy interval.

Back to blog