Skip to content

Infisical/winrm-client

 
 

Repository files navigation

winrm-client

npm version Build Status Build Status

⚠️ This is an updated fork of the original nodejs-winrm project that doesn't seem to be maintained anymore.

winrm-client is a production-ready NodeJS client to access WinRM (Windows Remote Management) SOAP web service. It allows to execute commands on target windows machines. Please visit Microsoft's WinRM site for WINRM details.

⬆️ Migration from nodejs-winrm

Replace shell and command with Shell and Command.

// CommonJS
const { Shell, Command } = require('winrm-client');
// ES6
import { Shell, Command } from 'winrm-client';

Installation

# Using npm
npm install winrm-client

# Using pnpm
pnpm add winrm-client

# Using yarn
yarn add winrm-client

Features

  • 🔁 Supports both CommonJS and ES6 modules.
  • 🏗️ Has types for all exported functions and interfaces.
  • 🔐 Supports both Basic and NTLM authentication (auto-detected based on username format)
  • 🔁 Supports interactive commands that can automatically respond to prompts using three types of detection methods: (see Interactive Commands)
    • Regex Patterns (traditional method)
    • Custom Sync Detectors (new)
    • Custom Async Detectors (new)
  • 🔍 Supports debug logging using the DEBUG environment variable (see Debug Logging)
  • 🧪 Supports testing (see Testing)

Supported NodeJS Versions

Supports NodeJS Version >= 16.0.0

Tested on NodeJS versions 16, 18, 20, and latest LTS.

Supported WinRM Versions

As of now Winrm Version 3 is tested.

> winrm id

IdentifyResponse
    ProtocolVersion = http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd
    ProductVendor = Microsoft Corporation
    ProductVersion = OS: 10.0.xxxx SP: 0.0 Stack: 3.0

Remote Installation

On the remote host, a PowerShell prompt, using the Run as Administrator option and paste in the following lines:

> winrm quickconfig
y
> winrm set winrm/config/service/Auth '@{Basic="true"}'
> winrm set winrm/config/service '@{AllowUnencrypted="true"}'
> winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="1024"}'

On the client side where NodeJS is installed

npm install winrm-client

Authentication

winrm-client supports two authentication methods that are automatically detected based on the username format:

Basic Authentication

Used for local usernames (no domain prefix). Requires enabling Basic auth on the WinRM service.

// Local username - uses Basic authentication
await runCommand('hostname', 'server', 'Administrator', 'password', 5985);

NTLM Authentication

Used for domain accounts. Automatically enabled when using domain-prefixed usernames.

// Domain prefix format (DOMAIN\user) - uses NTLM authentication
await runCommand(
  'hostname',
  'server',
  'DOMAIN\\Administrator',
  'password',
  5985
);

// UPN format (user@domain.com) - uses NTLM authentication
await runCommand('hostname', 'server', 'admin@company.com', 'password', 5985);

Username Format Support

Username Format Auth Method Example
Local Basic Administrator
Domain prefix NTLM DOMAIN\user
UPN NTLM user@domain.com

Remote Host Configuration for NTLM

For NTLM authentication, ensure the remote WinRM service allows Negotiate authentication:

# Enable Negotiate authentication (includes NTLM)
> winrm set winrm/config/service/Auth '@{Negotiate="true"}'

Development Workflow

For development with TypeScript:

# Install dependencies
npm install

# Build TypeScript to JavaScript
npm run build

# Watch mode for development
npm run build:watch

# Lint TypeScript files
npm run lint

# Format code with Prettier
npm run format

# Check formatting
npm run format:check

Debug Logging

To enable debug logging, set the DEBUG environment variable to winrm or winrm:*.

Possible values for namespace are:

  • * // Enable debug logging for all namespaces
  • http
  • shell
  • command
  • interactive
  • runCommand
  • runPowershell

To enable debug logging for all namespaces, set the DEBUG environment variable to winrm:*.

DEBUG=winrm:* node index.js

Examples

Run a Single Command

JavaScript

const winrm = require('winrm-client');
winrm.runCommand(
  'mkdir D:\\winrmtest001',
  '10.xxx.xxx.xxx',
  'username',
  'password',
  5985
);
winrm.runCommand(
  'ipconfig /all',
  '10.xxx.xxx.xxx',
  'username',
  'password',
  5985
);

TypeScript

import { runCommand, runPowershell } from 'winrm-client';

async function executeCommand(): Promise<void> {
  try {
    const result = await runCommand(
      'mkdir D:\\winrmtest001',
      '10.xxx.xxx.xxx',
      'username',
      'password',
      5985
    );
    console.log('Command result:', result);

    const ipResult = await runCommand(
      'ipconfig /all',
      '10.xxx.xxx.xxx',
      'username',
      'password',
      5985
    );
    console.log('IP Config:', ipResult);
  } catch (error) {
    console.error('Error executing command:', error);
  }
}

executeCommand();

Run Command with NTLM Authentication

For domain-joined machines or Azure AD accounts:

import { runCommand, runPowershell } from 'winrm-client';

async function executeDomainCommand(): Promise<void> {
  try {
    // Using DOMAIN\user format
    const result = await runCommand(
      'whoami',
      'server.company.com',
      'CORPORATE\\admin',
      'password',
      5985
    );
    console.log('Current user:', result);

    // Using UPN format (user@domain.com)
    const psResult = await runPowershell(
      'Get-Process | Select-Object -First 5',
      'server.company.com',
      'admin@corporate.local',
      'password',
      5985
    );
    console.log('Processes:', psResult);
  } catch (error) {
    console.error('Error:', error);
  }
}

executeDomainCommand();

Interactive Commands

WinRM Client supports interactive commands that can automatically respond to prompts using three types of detection methods:

  1. Regex Patterns (traditional method)
  2. Custom Sync Detectors (new)
  3. Custom Async Detectors (new)

Basic Interactive Command

const winrm = require('winrm-client');

const prompts = [
  {
    pattern: /Enter your name:/i,
    response: 'John Doe',
  },
  {
    pattern: /Password:/i,
    response: 'secret123',
    isSecure: true, // Won't log the response
  },
];

const result = await winrm.runInteractivePowershell(
  'my-interactive-script.ps1',
  'host',
  'username',
  'password',
  5985,
  prompts,
  30000 // timeout in milliseconds
);

Custom Sync Detectors

Use custom synchronous functions for complex prompt detection logic:

const prompts = [
  {
    detector: (output) => {
      // Custom logic for detecting prompts
      const lines = output.split('\n');
      return lines.some(
        (line) =>
          line.toLowerCase().includes('password') ||
          line.toLowerCase().includes('passphrase')
      );
    },
    response: 'myPassword123',
    isSecure: true,
  },
  {
    detector: (output) => {
      // Multi-condition detection
      return output.includes('Continue?') && output.includes('(y/n)');
    },
    response: 'y',
  },
];

Custom Async Detectors

Use async functions for detection that requires external API calls, LLM responses, database lookups, or other async operations:

const prompts = [
  {
    asyncDetector: async (output) => {
      // Example: External API validation
      const errorCodeMatch = output.match(/Error Code: (\d+)/);
      if (errorCodeMatch) {
        try {
          // Make external API call
          const response = await fetch(
            `https://api.example.com/errors/${errorCodeMatch[1]}`
          );
          const data = await response.json();
          return data.requiresConfirmation ? 'yes' : '';
        } catch {
          return 'no'; // Fallback to regex pattern if available
        }
      }
      return 'no';
    },
    pattern: /Do you want to retry/i, // Fallback pattern
  },
];

Detection Priority and Fallback

The detection methods are prioritized as follows:

  1. Async Detector (highest priority)
  2. Sync Detector
  3. Regex Pattern (fallback)

If a custom detector fails with an error, the system will automatically fall back to the regex pattern if available:

Error Handling

Custom detectors are wrapped in try-catch blocks to prevent failures from breaking the interactive flow:

  • If a custom detector throws an error, it falls back to the regex pattern
  • If both custom detector and regex pattern fail, the prompt is skipped
  • Errors are logged for debugging purposes

Testing

npm test

Test Server Setup (Windows)

For e2e testing, use the included setup script on a Windows Server (AWS EC2, etc.):

# Via SSH
ssh Administrator@<IP> "powershell -ExecutionPolicy Bypass" < scripts/setup-winrm.ps1

This configures WinRM + AD DS with a test user. See WINRM_SETUP.md for details.

Maintainers

About

Make WinRM service calls from NodeJS, interact and detect prompts using LLMs or matching patterns

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • TypeScript 88.3%
  • PowerShell 10.6%
  • JavaScript 1.1%