wangzhibo
2026-05-09 53418655c061ac26f66058253f39200aced1ab1d
1
{"version":3,"file":"azurePowerShellCredential.js","sourceRoot":"","sources":["../../../src/credentials/azurePowerShellCredential.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AccessToken, GetTokenOptions, TokenCredential } from \"@azure/core-auth\";\nimport {\n  checkTenantId,\n  processMultiTenantRequest,\n  resolveAdditionallyAllowedTenantIds,\n} from \"../util/tenantIdUtils.js\";\nimport { credentialLogger, formatError, formatSuccess } from \"../util/logging.js\";\nimport { ensureValidScopeForDevTimeCreds, getScopeResource } from \"../util/scopeUtils.js\";\n\nimport type { AzurePowerShellCredentialOptions } from \"./azurePowerShellCredentialOptions.js\";\nimport { CredentialUnavailableError } from \"../errors.js\";\nimport { processUtils } from \"../util/processUtils.js\";\nimport { tracingClient } from \"../util/tracing.js\";\n\nconst logger = credentialLogger(\"AzurePowerShellCredential\");\n\nconst isWindows = process.platform === \"win32\";\n\n/**\n * Returns a platform-appropriate command name by appending \".exe\" on Windows.\n *\n * @internal\n */\nexport function formatCommand(commandName: string): string {\n  if (isWindows) {\n    return `${commandName}.exe`;\n  } else {\n    return commandName;\n  }\n}\n\n/**\n * Receives a list of commands to run, executes them, then returns the outputs.\n * If anything fails, an error is thrown.\n * @internal\n */\nasync function runCommands(commands: string[][], timeout?: number): Promise<string[]> {\n  const results: string[] = [];\n\n  for (const command of commands) {\n    const [file, ...parameters] = command;\n    const result = (await processUtils.execFile(file, parameters, {\n      encoding: \"utf8\",\n      timeout,\n    })) as string;\n\n    results.push(result);\n  }\n\n  return results;\n}\n\n/**\n * Known PowerShell errors\n * @internal\n */\nexport const powerShellErrors = {\n  login: \"Run Connect-AzAccount to login\",\n  installed:\n    \"The specified module 'Az.Accounts' with version '2.2.0' was not loaded because no valid module file was found in any module directory\",\n};\n\n/**\n * Messages to use when throwing in this credential.\n * @internal\n */\nexport const powerShellPublicErrorMessages = {\n  login:\n    \"Please run 'Connect-AzAccount' from PowerShell to authenticate before using this credential.\",\n  installed: `The 'Az.Account' module >= 2.2.0 is not installed. Install the Azure Az PowerShell module with: \"Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force\".`,\n  claim:\n    \"This credential doesn't support claims challenges. To authenticate with the required claims, please run the following command:\",\n  troubleshoot: `To troubleshoot, visit https://aka.ms/azsdk/js/identity/powershellcredential/troubleshoot.`,\n};\n\n// PowerShell Azure User not logged in error check.\nconst isLoginError: (err: Error) => RegExpMatchArray | null = (err: Error) =>\n  err.message.match(`(.*)${powerShellErrors.login}(.*)`);\n\n// Az Module not Installed in Azure PowerShell check.\nconst isNotInstalledError: (err: Error) => RegExpMatchArray | null = (err: Error) =>\n  err.message.match(powerShellErrors.installed);\n\n/**\n * The PowerShell commands to be tried, in order.\n *\n * @internal\n */\nexport const commandStack = [formatCommand(\"pwsh\")];\n\nif (isWindows) {\n  commandStack.push(formatCommand(\"powershell\"));\n}\n\n/**\n * This credential will use the currently logged-in user information from the\n * Azure PowerShell module. To do so, it will read the user access token and\n * expire time with Azure PowerShell command `Get-AzAccessToken -ResourceUrl {ResourceScope}`\n */\nexport class AzurePowerShellCredential implements TokenCredential {\n  private tenantId?: string;\n  private additionallyAllowedTenantIds: string[];\n  private timeout?: number;\n\n  /**\n   * Creates an instance of the {@link AzurePowerShellCredential}.\n   *\n   * To use this credential:\n   * - Install the Azure Az PowerShell module with:\n   *   `Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force`.\n   * - You have already logged in to Azure PowerShell using the command\n   * `Connect-AzAccount` from the command line.\n   *\n   * @param options - Options, to optionally allow multi-tenant requests.\n   */\n  constructor(options?: AzurePowerShellCredentialOptions) {\n    if (options?.tenantId) {\n      checkTenantId(logger, options?.tenantId);\n      this.tenantId = options?.tenantId;\n    }\n    this.additionallyAllowedTenantIds = resolveAdditionallyAllowedTenantIds(\n      options?.additionallyAllowedTenants,\n    );\n    this.timeout = options?.processTimeoutInMs;\n  }\n\n  /**\n   * Gets the access token from Azure PowerShell\n   * @param resource - The resource to use when getting the token\n   */\n  private async getAzurePowerShellAccessToken(\n    resource: string,\n    tenantId?: string,\n    timeout?: number,\n  ): Promise<{ Token: string; ExpiresOn: string }> {\n    // Clone the stack to avoid mutating it while iterating\n    for (const powerShellCommand of [...commandStack]) {\n      try {\n        await runCommands([[powerShellCommand, \"/?\"]], timeout);\n      } catch (e: any) {\n        // Remove this credential from the original stack so that we don't try it again.\n        commandStack.shift();\n        continue;\n      }\n\n      const results = await runCommands([\n        [\n          powerShellCommand,\n          \"-NoProfile\",\n          \"-NonInteractive\",\n          \"-Command\",\n          `\n          $tenantId = \"${tenantId ?? \"\"}\"\n          $m = Import-Module Az.Accounts -MinimumVersion 2.2.0 -PassThru\n          $useSecureString = $m.Version -ge [version]'2.17.0' -and $m.Version -lt [version]'5.0.0'\n\n          $params = @{\n            ResourceUrl = \"${resource}\"\n          }\n\n          if ($tenantId.Length -gt 0) {\n            $params[\"TenantId\"] = $tenantId\n          }\n\n          if ($useSecureString) {\n            $params[\"AsSecureString\"] = $true\n          }\n\n          $token = Get-AzAccessToken @params\n\n          $result = New-Object -TypeName PSObject\n          $result | Add-Member -MemberType NoteProperty -Name ExpiresOn -Value $token.ExpiresOn\n\n          if ($token.Token -is [System.Security.SecureString]) {\n            if ($PSVersionTable.PSVersion.Major -lt 7) {\n              $ssPtr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($token.Token)\n              try {\n                $result | Add-Member -MemberType NoteProperty -Name Token -Value ([System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ssPtr))\n              }\n              finally {\n                [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ssPtr)\n              }\n            }\n            else {\n              $result | Add-Member -MemberType NoteProperty -Name Token -Value ($token.Token | ConvertFrom-SecureString -AsPlainText)\n            }\n          }\n          else {\n            $result | Add-Member -MemberType NoteProperty -Name Token -Value $token.Token\n          }\n\n          Write-Output (ConvertTo-Json $result)\n          `,\n        ],\n      ]);\n\n      const result = results[0];\n      return parseJsonToken(result);\n    }\n    throw new Error(`Unable to execute PowerShell. Ensure that it is installed in your system`);\n  }\n\n  /**\n   * Authenticates with Microsoft Entra ID and returns an access token if successful.\n   * If the authentication cannot be performed through PowerShell, a {@link CredentialUnavailableError} will be thrown.\n   *\n   * @param scopes - The list of scopes for which the token will have access.\n   * @param options - The options used to configure any requests this TokenCredential implementation might make.\n   */\n  public async getToken(\n    scopes: string | string[],\n    options: GetTokenOptions = {},\n  ): Promise<AccessToken> {\n    return tracingClient.withSpan(`${this.constructor.name}.getToken`, options, async () => {\n      const scope = typeof scopes === \"string\" ? scopes : scopes[0];\n\n      const claimsValue = options.claims;\n      if (claimsValue && claimsValue.trim()) {\n        const encodedClaims = btoa(claimsValue);\n        let loginCmd = `Connect-AzAccount -ClaimsChallenge ${encodedClaims}`;\n\n        const tenantIdFromOptions = options.tenantId;\n        if (tenantIdFromOptions) {\n          loginCmd += ` -Tenant ${tenantIdFromOptions}`;\n        }\n        const error = new CredentialUnavailableError(\n          `${powerShellPublicErrorMessages.claim} ${loginCmd}`,\n        );\n\n        logger.getToken.info(formatError(scope, error));\n        throw error;\n      }\n\n      const tenantId = processMultiTenantRequest(\n        this.tenantId,\n        options,\n        this.additionallyAllowedTenantIds,\n      );\n      if (tenantId) {\n        checkTenantId(logger, tenantId);\n      }\n      try {\n        ensureValidScopeForDevTimeCreds(scope, logger);\n        logger.getToken.info(`Using the scope ${scope}`);\n        const resource = getScopeResource(scope);\n        const response = await this.getAzurePowerShellAccessToken(resource, tenantId, this.timeout);\n        logger.getToken.info(formatSuccess(scopes));\n        return {\n          token: response.Token,\n          expiresOnTimestamp: new Date(response.ExpiresOn).getTime(),\n          tokenType: \"Bearer\",\n        } as AccessToken;\n      } catch (err: any) {\n        if (isNotInstalledError(err)) {\n          const error = new CredentialUnavailableError(powerShellPublicErrorMessages.installed);\n          logger.getToken.info(formatError(scope, error));\n          throw error;\n        } else if (isLoginError(err)) {\n          const error = new CredentialUnavailableError(powerShellPublicErrorMessages.login);\n          logger.getToken.info(formatError(scope, error));\n          throw error;\n        }\n        const error = new CredentialUnavailableError(\n          `${err}. ${powerShellPublicErrorMessages.troubleshoot}`,\n        );\n        logger.getToken.info(formatError(scope, error));\n        throw error;\n      }\n    });\n  }\n}\n\n/**\n *\n * @internal\n */\nexport async function parseJsonToken(\n  result: string,\n): Promise<{ Token: string; ExpiresOn: string }> {\n  const jsonRegex = /{[^{}]*}/g;\n  const matches = result.match(jsonRegex);\n  let resultWithoutToken = result;\n  if (matches) {\n    try {\n      for (const item of matches) {\n        try {\n          const jsonContent = JSON.parse(item);\n          if (jsonContent?.Token) {\n            resultWithoutToken = resultWithoutToken.replace(item, \"\");\n            if (resultWithoutToken) {\n              logger.getToken.warning(resultWithoutToken);\n            }\n            return jsonContent;\n          }\n        } catch (e) {\n          continue;\n        }\n      }\n    } catch (e: any) {\n      throw new Error(`Unable to parse the output of PowerShell. Received output: ${result}`);\n    }\n  }\n  throw new Error(`No access token found in the output. Received output: ${result}`);\n}\n"]}