From 215d975de5c98f9dd07db32cfc0e457a8dd79361 Mon Sep 17 00:00:00 2001 From: Yeming Liu <11371776+isra-fel@users.noreply.github.com> Date: Thu, 30 Jul 2026 10:40:28 +1000 Subject: [PATCH 1/4] Update CODEOWNERS (#598) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 27a83c107..f5081d1f8 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -@kaverma @kanika1894 @BALAGA-GAYATRI @pulkitaggarwl +@Azure/act-identity-squad \ No newline at end of file From 8a5b665a5ed87fbbf07e75a21970542f3885a7c5 Mon Sep 17 00:00:00 2001 From: MaddyMicrosoft Date: Thu, 30 Jul 2026 11:02:53 +1000 Subject: [PATCH 2/4] Add IDE files to .gitignore (#597) --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 18e337ddd..fef07358f 100644 --- a/.gitignore +++ b/.gitignore @@ -94,6 +94,12 @@ typings/ .DS_Store Thumbs.db +# IDE / editor +.vs/ +.vscode/ +.idea/ +*.swp + # Ignore built ts files __tests__/runner/* lib/**/* \ No newline at end of file From 971058802c3d30878057aea32c174a6c49374470 Mon Sep 17 00:00:00 2001 From: MaddyMicrosoft Date: Tue, 4 Aug 2026 11:21:18 +1000 Subject: [PATCH 3/4] Escape single quotes in PowerShell login script inputs (#599) Apply the same single-quote escape already used for the service principal secret to the remaining values interpolated into the generated PowerShell login script: tenant-id, subscription-id, client-id, federated token, and the AzureStack resourceManagerEndpointUrl. Factor the escape into a shared helper (escapePSSingleQuoted) so every interpolation site uses the same treatment, and add regression tests that assert each field is escaped across all supported auth paths. No behaviour change for valid inputs; legitimate values contain no single quotes. --- .../PowerShell/AzPSScriptBuilder.test.ts | 153 ++++++++++++++++++ src/PowerShell/AzPSScriptBuilder.ts | 28 +++- 2 files changed, 173 insertions(+), 8 deletions(-) diff --git a/__tests__/PowerShell/AzPSScriptBuilder.test.ts b/__tests__/PowerShell/AzPSScriptBuilder.test.ts index 862d7a0f5..76b32c244 100644 --- a/__tests__/PowerShell/AzPSScriptBuilder.test.ts +++ b/__tests__/PowerShell/AzPSScriptBuilder.test.ts @@ -150,4 +150,157 @@ describe("Getting AzLogin PS script", () => { }); }); + const INJECT_RAW = "abc' ; Start-Process calc ; $x='"; + const INJECT_ESCAPED = "abc'' ; Start-Process calc ; $x=''"; + + test('SECURITY: tenant-id single quote is escaped (SP+secret path)', () => { + setEnv('environment', 'azurecloud'); + setEnv('enable-AzPSSession', 'true'); + setEnv('allow-no-subscriptions', 'true'); + setEnv('auth-type', 'SERVICE_PRINCIPAL'); + let creds = { + 'clientId': 'client-id', + 'clientSecret': 'client-secret', + 'tenantId': INJECT_RAW, + 'subscriptionId': 'subscription-id' + } + setEnv('creds', JSON.stringify(creds)); + + let loginConfig = new LoginConfig(); + loginConfig.initialize(); + return AzPSSCriptBuilder.getAzPSLoginScript(loginConfig).then(([_, loginScript]) => { + expect(loginScript).toContain(`-Tenant '${INJECT_ESCAPED}'`); + expect(loginScript).not.toContain(`-Tenant '${INJECT_RAW}'`); + }); + }); + + test('SECURITY: subscription-id single quote is escaped (SP+secret path)', () => { + setEnv('environment', 'azurecloud'); + setEnv('enable-AzPSSession', 'true'); + setEnv('allow-no-subscriptions', 'true'); + setEnv('auth-type', 'SERVICE_PRINCIPAL'); + let creds = { + 'clientId': 'client-id', + 'clientSecret': 'client-secret', + 'tenantId': 'tenant-id', + 'subscriptionId': INJECT_RAW + } + setEnv('creds', JSON.stringify(creds)); + + let loginConfig = new LoginConfig(); + loginConfig.initialize(); + return AzPSSCriptBuilder.getAzPSLoginScript(loginConfig).then(([_, loginScript]) => { + expect(loginScript).toContain(`-Subscription '${INJECT_ESCAPED}'`); + expect(loginScript).not.toContain(`-Subscription '${INJECT_RAW}'`); + }); + }); + + test('SECURITY: client-id single quote is escaped (SP+secret path, PSCredential)', () => { + setEnv('environment', 'azurecloud'); + setEnv('enable-AzPSSession', 'true'); + setEnv('allow-no-subscriptions', 'true'); + setEnv('auth-type', 'SERVICE_PRINCIPAL'); + let creds = { + 'clientId': INJECT_RAW, + 'clientSecret': 'client-secret', + 'tenantId': 'tenant-id', + 'subscriptionId': 'subscription-id' + } + setEnv('creds', JSON.stringify(creds)); + + let loginConfig = new LoginConfig(); + loginConfig.initialize(); + return AzPSSCriptBuilder.getAzPSLoginScript(loginConfig).then(([_, loginScript]) => { + expect(loginScript).toContain(`New-Object System.Management.Automation.PSCredential('${INJECT_ESCAPED}',`); + expect(loginScript).not.toContain(`New-Object System.Management.Automation.PSCredential('${INJECT_RAW}',`); + }); + }); + + test('SECURITY: client-id single quote is escaped (OIDC path)', () => { + setEnv('environment', 'azurecloud'); + setEnv('enable-AzPSSession', 'true'); + setEnv('allow-no-subscriptions', 'false'); + setEnv('tenant-id', 'tenant-id'); + setEnv('subscription-id', 'subscription-id'); + setEnv('client-id', INJECT_RAW); + setEnv('auth-type', 'SERVICE_PRINCIPAL'); + + let loginConfig = new LoginConfig(); + loginConfig.initialize(); + jest.spyOn(loginConfig, 'getFederatedToken').mockImplementation(async () => { loginConfig.federatedToken = "fake-token"; }); + return AzPSSCriptBuilder.getAzPSLoginScript(loginConfig).then(([_, loginScript]) => { + expect(loginScript).toContain(`-ApplicationId '${INJECT_ESCAPED}'`); + expect(loginScript).not.toContain(`-ApplicationId '${INJECT_RAW}'`); + }); + }); + + test('SECURITY: client-id single quote is escaped (user-assigned MI path)', () => { + setEnv('environment', 'azurecloud'); + setEnv('enable-AzPSSession', 'true'); + setEnv('allow-no-subscriptions', 'true'); + setEnv('auth-type', 'IDENTITY'); + setEnv('client-id', INJECT_RAW); + + let loginConfig = new LoginConfig(); + loginConfig.initialize(); + return AzPSSCriptBuilder.getAzPSLoginScript(loginConfig).then(([_, loginScript]) => { + expect(loginScript).toContain(`-AccountId '${INJECT_ESCAPED}'`); + expect(loginScript).not.toContain(`-AccountId '${INJECT_RAW}'`); + }); + }); + + test('SECURITY: tenant-id and subscription-id single quotes are escaped (system-assigned MI path)', () => { + setEnv('environment', 'azurecloud'); + setEnv('enable-AzPSSession', 'true'); + setEnv('allow-no-subscriptions', 'false'); + setEnv('tenant-id', INJECT_RAW); + setEnv('subscription-id', INJECT_RAW); + setEnv('auth-type', 'IDENTITY'); + + let loginConfig = new LoginConfig(); + loginConfig.initialize(); + return AzPSSCriptBuilder.getAzPSLoginScript(loginConfig).then(([_, loginScript]) => { + expect(loginScript).toContain(`-Tenant '${INJECT_ESCAPED}'`); + expect(loginScript).toContain(`-Subscription '${INJECT_ESCAPED}'`); + expect(loginScript).not.toContain(`-Tenant '${INJECT_RAW}'`); + expect(loginScript).not.toContain(`-Subscription '${INJECT_RAW}'`); + }); + }); + + test('SECURITY: resourceManagerEndpointUrl single quote is escaped (AzureStack path)', () => { + setEnv('environment', 'azurestack'); + setEnv('enable-AzPSSession', 'true'); + setEnv('allow-no-subscriptions', 'true'); + setEnv('auth-type', 'SERVICE_PRINCIPAL'); + let creds = { + 'clientId': 'client-id', + 'clientSecret': 'client-secret', + 'tenantId': 'tenant-id', + 'subscriptionId': 'subscription-id', + 'resourceManagerEndpointUrl': INJECT_RAW + } + setEnv('creds', JSON.stringify(creds)); + + let loginConfig = new LoginConfig(); + loginConfig.initialize(); + return AzPSSCriptBuilder.getAzPSLoginScript(loginConfig).then(([_, loginScript]) => { + expect(loginScript).toContain(`-ARMEndpoint '${INJECT_ESCAPED}'`); + expect(loginScript).not.toContain(`-ARMEndpoint '${INJECT_RAW}'`); + }); + }); + + test('SECURITY: escapePSSingleQuoted handles null/undefined without throwing', () => { + setEnv('environment', 'azurecloud'); + setEnv('enable-AzPSSession', 'true'); + setEnv('allow-no-subscriptions', 'false'); + setEnv('auth-type', 'IDENTITY'); + + let loginConfig = new LoginConfig(); + loginConfig.initialize(); + return AzPSSCriptBuilder.getAzPSLoginScript(loginConfig).then(([loginMethod, loginScript]) => { + expect(loginScript).toContain("Connect-AzAccount -Identity -Environment 'azurecloud'"); + expect(loginMethod).toBe('system-assigned managed identity'); + }); + }); + }); \ No newline at end of file diff --git a/src/PowerShell/AzPSScriptBuilder.ts b/src/PowerShell/AzPSScriptBuilder.ts index 5cd34580f..8b6b05824 100644 --- a/src/PowerShell/AzPSScriptBuilder.ts +++ b/src/PowerShell/AzPSScriptBuilder.ts @@ -21,12 +21,20 @@ export default class AzPSScriptBuilder { return script; } + // Doubles single quotes for safe interpolation into a PowerShell '...' literal. + private static escapePSSingleQuoted(value: string): string { + if (value === null || value === undefined) { + return ""; + } + return String(value).split("'").join("''"); + } + static async getAzPSLoginScript(loginConfig: LoginConfig) { let loginMethodName = ""; let commands = ""; if (loginConfig.environment.toLowerCase() == "azurestack") { - commands += `Add-AzEnvironment -Name '${loginConfig.environment}' -ARMEndpoint '${loginConfig.resourceManagerEndpointUrl}' | out-null;`; + commands += `Add-AzEnvironment -Name '${loginConfig.environment}' -ARMEndpoint '${AzPSScriptBuilder.escapePSSingleQuoted(loginConfig.resourceManagerEndpointUrl)}' | out-null;`; } if (loginConfig.authType === LoginConfig.AUTH_TYPE_SERVICE_PRINCIPAL) { if (loginConfig.servicePrincipalSecret) { @@ -64,10 +72,11 @@ export default class AzPSScriptBuilder { } private static loginWithSecret(loginConfig: LoginConfig): string { - let servicePrincipalSecret: string = loginConfig.servicePrincipalSecret.split("'").join("''"); + let servicePrincipalSecret: string = AzPSScriptBuilder.escapePSSingleQuoted(loginConfig.servicePrincipalSecret); + let servicePrincipalId: string = AzPSScriptBuilder.escapePSSingleQuoted(loginConfig.servicePrincipalId); let loginCmdlet = `$psLoginSecrets = ConvertTo-SecureString '${servicePrincipalSecret}' -AsPlainText -Force; `; - loginCmdlet += `$psLoginCredential = New-Object System.Management.Automation.PSCredential('${loginConfig.servicePrincipalId}', $psLoginSecrets); `; - + loginCmdlet += `$psLoginCredential = New-Object System.Management.Automation.PSCredential('${servicePrincipalId}', $psLoginSecrets); `; + let cmdletSuffix = "-Credential $psLoginCredential"; loginCmdlet += AzPSScriptBuilder.psLoginCmdlet(loginConfig.authType, loginConfig.environment, loginConfig.tenantId, loginConfig.subscriptionId, cmdletSuffix); @@ -76,7 +85,9 @@ export default class AzPSScriptBuilder { private static async loginWithOIDC(loginConfig: LoginConfig) { await loginConfig.getFederatedToken(); - let cmdletSuffix = `-ApplicationId '${loginConfig.servicePrincipalId}' -FederatedToken '${loginConfig.federatedToken}'`; + let servicePrincipalId: string = AzPSScriptBuilder.escapePSSingleQuoted(loginConfig.servicePrincipalId); + let federatedToken: string = AzPSScriptBuilder.escapePSSingleQuoted(loginConfig.federatedToken); + let cmdletSuffix = `-ApplicationId '${servicePrincipalId}' -FederatedToken '${federatedToken}'`; return AzPSScriptBuilder.psLoginCmdlet(loginConfig.authType, loginConfig.environment, loginConfig.tenantId, loginConfig.subscriptionId, cmdletSuffix); } @@ -86,7 +97,8 @@ export default class AzPSScriptBuilder { } static loginWithUserAssignedIdentity(loginConfig: LoginConfig): string { - let cmdletSuffix = `-AccountId '${loginConfig.servicePrincipalId}'`; + let servicePrincipalId: string = AzPSScriptBuilder.escapePSSingleQuoted(loginConfig.servicePrincipalId); + let cmdletSuffix = `-AccountId '${servicePrincipalId}'`; return AzPSScriptBuilder.psLoginCmdlet(loginConfig.authType, loginConfig.environment, loginConfig.tenantId, loginConfig.subscriptionId, cmdletSuffix); } @@ -99,10 +111,10 @@ export default class AzPSScriptBuilder { } loginCmdlet += `-Environment '${environment}' `; if(tenantId){ - loginCmdlet += `-Tenant '${tenantId}' `; + loginCmdlet += `-Tenant '${AzPSScriptBuilder.escapePSSingleQuoted(tenantId)}' `; } if(subscriptionId){ - loginCmdlet += `-Subscription '${subscriptionId}' `; + loginCmdlet += `-Subscription '${AzPSScriptBuilder.escapePSSingleQuoted(subscriptionId)}' `; } loginCmdlet += `${cmdletSuffix} -InformationAction Ignore | out-null;`; return loginCmdlet; From 7184910d9eb2b1c5e48f7073824a90609bb9b6d6 Mon Sep 17 00:00:00 2001 From: Maddison Das <272712104+MaddyMicrosoft@users.noreply.github.com> Date: Tue, 4 Aug 2026 12:34:30 +1000 Subject: [PATCH 4/4] prepare release v2.3.1 --- lib/cleanup/index.js | 25 ++++++++++++++++++------- lib/main/index.js | 25 ++++++++++++++++++------- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/lib/cleanup/index.js b/lib/cleanup/index.js index 75261a874..fd036fb64 100644 --- a/lib/cleanup/index.js +++ b/lib/cleanup/index.js @@ -3974,12 +3974,19 @@ class AzPSScriptBuilder { return ConvertTo-Json $output`; return script; } + // Doubles single quotes for safe interpolation into a PowerShell '...' literal. + static escapePSSingleQuoted(value) { + if (value === null || value === undefined) { + return ""; + } + return String(value).split("'").join("''"); + } static getAzPSLoginScript(loginConfig) { return __awaiter(this, void 0, void 0, function* () { let loginMethodName = ""; let commands = ""; if (loginConfig.environment.toLowerCase() == "azurestack") { - commands += `Add-AzEnvironment -Name '${loginConfig.environment}' -ARMEndpoint '${loginConfig.resourceManagerEndpointUrl}' | out-null;`; + commands += `Add-AzEnvironment -Name '${loginConfig.environment}' -ARMEndpoint '${AzPSScriptBuilder.escapePSSingleQuoted(loginConfig.resourceManagerEndpointUrl)}' | out-null;`; } if (loginConfig.authType === LoginConfig_1.LoginConfig.AUTH_TYPE_SERVICE_PRINCIPAL) { if (loginConfig.servicePrincipalSecret) { @@ -4018,9 +4025,10 @@ class AzPSScriptBuilder { }); } static loginWithSecret(loginConfig) { - let servicePrincipalSecret = loginConfig.servicePrincipalSecret.split("'").join("''"); + let servicePrincipalSecret = AzPSScriptBuilder.escapePSSingleQuoted(loginConfig.servicePrincipalSecret); + let servicePrincipalId = AzPSScriptBuilder.escapePSSingleQuoted(loginConfig.servicePrincipalId); let loginCmdlet = `$psLoginSecrets = ConvertTo-SecureString '${servicePrincipalSecret}' -AsPlainText -Force; `; - loginCmdlet += `$psLoginCredential = New-Object System.Management.Automation.PSCredential('${loginConfig.servicePrincipalId}', $psLoginSecrets); `; + loginCmdlet += `$psLoginCredential = New-Object System.Management.Automation.PSCredential('${servicePrincipalId}', $psLoginSecrets); `; let cmdletSuffix = "-Credential $psLoginCredential"; loginCmdlet += AzPSScriptBuilder.psLoginCmdlet(loginConfig.authType, loginConfig.environment, loginConfig.tenantId, loginConfig.subscriptionId, cmdletSuffix); return loginCmdlet; @@ -4028,7 +4036,9 @@ class AzPSScriptBuilder { static loginWithOIDC(loginConfig) { return __awaiter(this, void 0, void 0, function* () { yield loginConfig.getFederatedToken(); - let cmdletSuffix = `-ApplicationId '${loginConfig.servicePrincipalId}' -FederatedToken '${loginConfig.federatedToken}'`; + let servicePrincipalId = AzPSScriptBuilder.escapePSSingleQuoted(loginConfig.servicePrincipalId); + let federatedToken = AzPSScriptBuilder.escapePSSingleQuoted(loginConfig.federatedToken); + let cmdletSuffix = `-ApplicationId '${servicePrincipalId}' -FederatedToken '${federatedToken}'`; return AzPSScriptBuilder.psLoginCmdlet(loginConfig.authType, loginConfig.environment, loginConfig.tenantId, loginConfig.subscriptionId, cmdletSuffix); }); } @@ -4037,7 +4047,8 @@ class AzPSScriptBuilder { return AzPSScriptBuilder.psLoginCmdlet(loginConfig.authType, loginConfig.environment, loginConfig.tenantId, loginConfig.subscriptionId, cmdletSuffix); } static loginWithUserAssignedIdentity(loginConfig) { - let cmdletSuffix = `-AccountId '${loginConfig.servicePrincipalId}'`; + let servicePrincipalId = AzPSScriptBuilder.escapePSSingleQuoted(loginConfig.servicePrincipalId); + let cmdletSuffix = `-AccountId '${servicePrincipalId}'`; return AzPSScriptBuilder.psLoginCmdlet(loginConfig.authType, loginConfig.environment, loginConfig.tenantId, loginConfig.subscriptionId, cmdletSuffix); } static psLoginCmdlet(authType, environment, tenantId, subscriptionId, cmdletSuffix) { @@ -4050,10 +4061,10 @@ class AzPSScriptBuilder { } loginCmdlet += `-Environment '${environment}' `; if (tenantId) { - loginCmdlet += `-Tenant '${tenantId}' `; + loginCmdlet += `-Tenant '${AzPSScriptBuilder.escapePSSingleQuoted(tenantId)}' `; } if (subscriptionId) { - loginCmdlet += `-Subscription '${subscriptionId}' `; + loginCmdlet += `-Subscription '${AzPSScriptBuilder.escapePSSingleQuoted(subscriptionId)}' `; } loginCmdlet += `${cmdletSuffix} -InformationAction Ignore | out-null;`; return loginCmdlet; diff --git a/lib/main/index.js b/lib/main/index.js index 056b83dee..a1d70dee0 100644 --- a/lib/main/index.js +++ b/lib/main/index.js @@ -4261,12 +4261,19 @@ class AzPSScriptBuilder { return ConvertTo-Json $output`; return script; } + // Doubles single quotes for safe interpolation into a PowerShell '...' literal. + static escapePSSingleQuoted(value) { + if (value === null || value === undefined) { + return ""; + } + return String(value).split("'").join("''"); + } static getAzPSLoginScript(loginConfig) { return __awaiter(this, void 0, void 0, function* () { let loginMethodName = ""; let commands = ""; if (loginConfig.environment.toLowerCase() == "azurestack") { - commands += `Add-AzEnvironment -Name '${loginConfig.environment}' -ARMEndpoint '${loginConfig.resourceManagerEndpointUrl}' | out-null;`; + commands += `Add-AzEnvironment -Name '${loginConfig.environment}' -ARMEndpoint '${AzPSScriptBuilder.escapePSSingleQuoted(loginConfig.resourceManagerEndpointUrl)}' | out-null;`; } if (loginConfig.authType === LoginConfig_1.LoginConfig.AUTH_TYPE_SERVICE_PRINCIPAL) { if (loginConfig.servicePrincipalSecret) { @@ -4305,9 +4312,10 @@ class AzPSScriptBuilder { }); } static loginWithSecret(loginConfig) { - let servicePrincipalSecret = loginConfig.servicePrincipalSecret.split("'").join("''"); + let servicePrincipalSecret = AzPSScriptBuilder.escapePSSingleQuoted(loginConfig.servicePrincipalSecret); + let servicePrincipalId = AzPSScriptBuilder.escapePSSingleQuoted(loginConfig.servicePrincipalId); let loginCmdlet = `$psLoginSecrets = ConvertTo-SecureString '${servicePrincipalSecret}' -AsPlainText -Force; `; - loginCmdlet += `$psLoginCredential = New-Object System.Management.Automation.PSCredential('${loginConfig.servicePrincipalId}', $psLoginSecrets); `; + loginCmdlet += `$psLoginCredential = New-Object System.Management.Automation.PSCredential('${servicePrincipalId}', $psLoginSecrets); `; let cmdletSuffix = "-Credential $psLoginCredential"; loginCmdlet += AzPSScriptBuilder.psLoginCmdlet(loginConfig.authType, loginConfig.environment, loginConfig.tenantId, loginConfig.subscriptionId, cmdletSuffix); return loginCmdlet; @@ -4315,7 +4323,9 @@ class AzPSScriptBuilder { static loginWithOIDC(loginConfig) { return __awaiter(this, void 0, void 0, function* () { yield loginConfig.getFederatedToken(); - let cmdletSuffix = `-ApplicationId '${loginConfig.servicePrincipalId}' -FederatedToken '${loginConfig.federatedToken}'`; + let servicePrincipalId = AzPSScriptBuilder.escapePSSingleQuoted(loginConfig.servicePrincipalId); + let federatedToken = AzPSScriptBuilder.escapePSSingleQuoted(loginConfig.federatedToken); + let cmdletSuffix = `-ApplicationId '${servicePrincipalId}' -FederatedToken '${federatedToken}'`; return AzPSScriptBuilder.psLoginCmdlet(loginConfig.authType, loginConfig.environment, loginConfig.tenantId, loginConfig.subscriptionId, cmdletSuffix); }); } @@ -4324,7 +4334,8 @@ class AzPSScriptBuilder { return AzPSScriptBuilder.psLoginCmdlet(loginConfig.authType, loginConfig.environment, loginConfig.tenantId, loginConfig.subscriptionId, cmdletSuffix); } static loginWithUserAssignedIdentity(loginConfig) { - let cmdletSuffix = `-AccountId '${loginConfig.servicePrincipalId}'`; + let servicePrincipalId = AzPSScriptBuilder.escapePSSingleQuoted(loginConfig.servicePrincipalId); + let cmdletSuffix = `-AccountId '${servicePrincipalId}'`; return AzPSScriptBuilder.psLoginCmdlet(loginConfig.authType, loginConfig.environment, loginConfig.tenantId, loginConfig.subscriptionId, cmdletSuffix); } static psLoginCmdlet(authType, environment, tenantId, subscriptionId, cmdletSuffix) { @@ -4337,10 +4348,10 @@ class AzPSScriptBuilder { } loginCmdlet += `-Environment '${environment}' `; if (tenantId) { - loginCmdlet += `-Tenant '${tenantId}' `; + loginCmdlet += `-Tenant '${AzPSScriptBuilder.escapePSSingleQuoted(tenantId)}' `; } if (subscriptionId) { - loginCmdlet += `-Subscription '${subscriptionId}' `; + loginCmdlet += `-Subscription '${AzPSScriptBuilder.escapePSSingleQuoted(subscriptionId)}' `; } loginCmdlet += `${cmdletSuffix} -InformationAction Ignore | out-null;`; return loginCmdlet;