Я впервые пытаюсь создать файл DSC (требуемая конфигурация состояния) с шаблоном ARM (Azure Resource Manager) для развертывания Windows Server 2016, и до сих пор все работало отлично, пока я не попытался передать имя пользователя/ пароль, чтобы я мог создать локальную учетную запись пользователя Windows.Кажется, я вообще не могу выполнить эту функцию (см. Сообщение об ошибке ниже).
Мой вопрос: как использовать шаблон ARM, чтобы извлечь пароль из хранилища ключей Azure и передать его вРасширение DSC powershell?
Вот мои текущие настройки:
azuredeploy.json
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"deployExecUsername": {
"type": "string",
"defaultValue": "DeployExec"
},
"deployExecPassword": {
"type": "securestring"
},
"_artifactsLocation": {
"type": "string",
"metadata": {
"description": "Auto-generated container in staging storage account to receive post-build staging folder upload"
}
},
"_artifactsLocationSasToken": {
"type": "securestring",
"metadata": {
"description": "Auto-generated token to access _artifactsLocation"
}
},
"virtualMachineName": {
"type": "string",
"defaultValue": "web-app-server"
}
},
"variables": {
"CreateLocalUserArchiveFolder": "DSC",
"CreateLocalUserArchiveFileName": "CreateLocalUser.zip"},
"resources": [
{
"name": "[concat(parameters('virtualMachineName'), '/', 'Microsoft.Powershell.DSC')]",
"type": "Microsoft.Compute/virtualMachines/extensions",
"location": "eastus2",
"apiVersion": "2016-03-30",
"dependsOn": [ ],
"tags": {
"displayName": "CreateLocalUser"
},
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.9",
"autoUpgradeMinorVersion": true,
"settings": {
"configuration": {
"url": "[concat(parameters('_artifactsLocation'), '/', variables('CreateLocalUserArchiveFolder'), '/', variables('CreateLocalUserArchiveFileName'))]",
"script": "CreateLocalUser.ps1",
"function": "Main"
},
"configurationArguments": {
"nodeName": "[parameters('virtualMachineName')]"
}
},
"protectedSettings": {
"configurationArguments": {
"deployExecCredential": {
"UserName": "[parameters('deployExecUsername')]",
"Password": "[parameters('deployExecPassword')]"
}
},
"configurationUrlSasToken": "[parameters('_artifactsLocationSasToken')]"
}
}
}],
"outputs": {}
}
azuredeploy.parameters.json
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"deployExecPassword": {
"reference": {
"keyVault": {
"id": "/subscriptions/<GUID>/resourceGroups/<Resource Group Name>/providers/Microsoft.KeyVault/vaults/<Resource Group Name>-key-vault"
},
"secretName": "web-app-server-deployexec-password"
}
}
}
}
DSC /CreateLocalUser.ps1
Configuration Main
{
Param (
[string] $nodeName,
[PSCredential]$deployExecCredential
)
Import-DscResource -ModuleName PSDesiredStateConfiguration
Node $nodeName
{
User DeployExec
{
Ensure = "Present"
Description = "Deployment account for Web Deploy"
UserName = $deployExecCredential.UserName
Password = $deployExecCredential
PasswordNeverExpires = $true
PasswordChangeRequired = $false
PasswordChangeNotAllowed = $true
}
}
}
Deploy-AzureResourceGroup.ps1 (по умолчанию из шаблона группы ресурсов Azure)
#Requires -Version 3.0
Param(
[string] [Parameter(Mandatory=$true)] $ResourceGroupLocation,
[string] $ResourceGroupName = 'AzureResourceGroup2',
[switch] $UploadArtifacts,
[string] $StorageAccountName,
[string] $StorageContainerName = $ResourceGroupName.ToLowerInvariant() + '-stageartifacts',
[string] $TemplateFile = 'azuredeploy.json',
[string] $TemplateParametersFile = 'azuredeploy.parameters.json',
[string] $ArtifactStagingDirectory = '.',
[string] $DSCSourceFolder = 'DSC',
[switch] $ValidateOnly
)
try {
[Microsoft.Azure.Common.Authentication.AzureSession]::ClientFactory.AddUserAgent("VSAzureTools-$UI$($host.name)".replace(' ','_'), '3.0.0')
} catch { }
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version 3
function Format-ValidationOutput {
param ($ValidationOutput, [int] $Depth = 0)
Set-StrictMode -Off
return @($ValidationOutput | Where-Object { $_ -ne $null } | ForEach-Object { @(' ' * $Depth + ': ' + $_.Message) + @(Format-ValidationOutput @($_.Details) ($Depth + 1)) })
}
$OptionalParameters = New-Object -TypeName Hashtable
$TemplateFile = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $TemplateFile))
$TemplateParametersFile = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $TemplateParametersFile))
if ($UploadArtifacts) {
# Convert relative paths to absolute paths if needed
$ArtifactStagingDirectory = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $ArtifactStagingDirectory))
$DSCSourceFolder = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $DSCSourceFolder))
# Parse the parameter file and update the values of artifacts location and artifacts location SAS token if they are present
$JsonParameters = Get-Content $TemplateParametersFile -Raw | ConvertFrom-Json
if (($JsonParameters | Get-Member -Type NoteProperty 'parameters') -ne $null) {
$JsonParameters = $JsonParameters.parameters
}
$ArtifactsLocationName = '_artifactsLocation'
$ArtifactsLocationSasTokenName = '_artifactsLocationSasToken'
$OptionalParameters[$ArtifactsLocationName] = $JsonParameters | Select -Expand $ArtifactsLocationName -ErrorAction Ignore | Select -Expand 'value' -ErrorAction Ignore
$OptionalParameters[$ArtifactsLocationSasTokenName] = $JsonParameters | Select -Expand $ArtifactsLocationSasTokenName -ErrorAction Ignore | Select -Expand 'value' -ErrorAction Ignore
# Create DSC configuration archive
if (Test-Path $DSCSourceFolder) {
$DSCSourceFilePaths = @(Get-ChildItem $DSCSourceFolder -File -Filter '*.ps1' | ForEach-Object -Process {$_.FullName})
foreach ($DSCSourceFilePath in $DSCSourceFilePaths) {
$DSCArchiveFilePath = $DSCSourceFilePath.Substring(0, $DSCSourceFilePath.Length - 4) + '.zip'
Publish-AzureRmVMDscConfiguration $DSCSourceFilePath -OutputArchivePath $DSCArchiveFilePath -Force -Verbose
}
}
# Create a storage account name if none was provided
if ($StorageAccountName -eq '') {
$StorageAccountName = 'stage' + ((Get-AzureRmContext).Subscription.SubscriptionId).Replace('-', '').substring(0, 19)
}
$StorageAccount = (Get-AzureRmStorageAccount | Where-Object{$_.StorageAccountName -eq $StorageAccountName})
# Create the storage account if it doesn't already exist
if ($StorageAccount -eq $null) {
$StorageResourceGroupName = 'ARM_Deploy_Staging'
New-AzureRmResourceGroup -Location "$ResourceGroupLocation" -Name $StorageResourceGroupName -Force
$StorageAccount = New-AzureRmStorageAccount -StorageAccountName $StorageAccountName -Type 'Standard_LRS' -ResourceGroupName $StorageResourceGroupName -Location "$ResourceGroupLocation"
}
# Generate the value for artifacts location if it is not provided in the parameter file
if ($OptionalParameters[$ArtifactsLocationName] -eq $null) {
$OptionalParameters[$ArtifactsLocationName] = $StorageAccount.Context.BlobEndPoint + $StorageContainerName
}
# Copy files from the local storage staging location to the storage account container
New-AzureStorageContainer -Name $StorageContainerName -Context $StorageAccount.Context -ErrorAction SilentlyContinue *>&1
$ArtifactFilePaths = Get-ChildItem $ArtifactStagingDirectory -Recurse -File | ForEach-Object -Process {$_.FullName}
foreach ($SourcePath in $ArtifactFilePaths) {
Set-AzureStorageBlobContent -File $SourcePath -Blob $SourcePath.Substring($ArtifactStagingDirectory.length + 1) `
-Container $StorageContainerName -Context $StorageAccount.Context -Force
}
# Generate a 4 hour SAS token for the artifacts location if one was not provided in the parameters file
if ($OptionalParameters[$ArtifactsLocationSasTokenName] -eq $null) {
$OptionalParameters[$ArtifactsLocationSasTokenName] = ConvertTo-SecureString -AsPlainText -Force `
(New-AzureStorageContainerSASToken -Container $StorageContainerName -Context $StorageAccount.Context -Permission r -ExpiryTime (Get-Date).AddHours(4))
}
}
# Create or update the resource group using the specified template file and template parameters file
New-AzureRmResourceGroup -Name $ResourceGroupName -Location $ResourceGroupLocation -Verbose -Force
if ($ValidateOnly) {
$ErrorMessages = Format-ValidationOutput (Test-AzureRmResourceGroupDeployment -ResourceGroupName $ResourceGroupName `
-TemplateFile $TemplateFile `
-TemplateParameterFile $TemplateParametersFile `
@OptionalParameters)
if ($ErrorMessages) {
Write-Output '', 'Validation returned the following errors:', @($ErrorMessages), '', 'Template is invalid.'
}
else {
Write-Output '', 'Template is valid.'
}
}
else {
New-AzureRmResourceGroupDeployment -Name ((Get-ChildItem $TemplateFile).BaseName + '-' + ((Get-Date).ToUniversalTime()).ToString('MMdd-HHmm')) `
-ResourceGroupName $ResourceGroupName `
-TemplateFile $TemplateFile `
-TemplateParameterFile $TemplateParametersFile `
@OptionalParameters `
-Force -Verbose `
-ErrorVariable ErrorMessages
if ($ErrorMessages) {
Write-Output '', 'Template deployment returned the following errors:', @(@($ErrorMessages) | ForEach-Object { $_.Exception.Message.TrimEnd("`r`n") })
}
}
Обратите внимание, что мой исходный шаблон развертывает весь сервер, но я могувоспроизведите проблему, с которой я столкнулся, с помощью вышеуказанного шаблона и любой старой виртуальной машины Windows Server 2016.
Я запускаю шаблон в сообществе Visual Studio 2017:
Шаблон проверяется и запускается, но при его запуске появляется следующее сообщение об ошибке:
22:26:41 - New-AzureRmResourceGroupDeployment : 10:26:41 PM - VM has reported a failure when processing extension
22:26:41 - 'Microsoft.Powershell.DSC'. Error message: "The DSC Extension received an incorrect input: Compilation errors occurred
22:26:41 - while processing configuration 'Main'. Please review the errors reported in error stream and modify your configuration
22:26:41 - code appropriately. System.InvalidOperationException error processing property 'Password' OF TYPE 'User': Converting
22:26:41 - and storing encrypted passwords as plain text is not recommended. For more information on securing credentials in MOF
22:26:41 - file, please refer to MSDN blog: http://go.microsoft.com/fwlink/?LinkId=393729
22:26:41 - At C:\Packages\Plugins\Microsoft.Powershell.DSC\2.77.0.0\DSCWork\CreateLocalUser.4\CreateLocalUser.ps1:12 char:3
22:26:41 - + User Converting and storing encrypted passwords as plain text is not recommended. For more information on securing
22:26:41 - credentials in MOF file, please refer to MSDN blog: http://go.microsoft.com/fwlink/?LinkId=393729 Cannot find path
22:26:41 - 'HKLM:\SOFTWARE\Microsoft\PowerShell\3\DSC' because it does not exist. Cannot find path
22:26:41 - 'HKLM:\SOFTWARE\Microsoft\PowerShell\3\DSC' because it does not exist.
22:26:41 - Another common error is to specify parameters of type PSCredential without an explicit type. Please be sure to use a
22:26:41 - typed parameter in DSC Configuration, for example:
22:26:41 - configuration Example {
22:26:41 - param([PSCredential] $UserAccount)
22:26:41 - ...
22:26:41 - }.
22:26:41 - Please correct the input and retry executing the extension.".
22:26:41 - At F:\Users\Shad\Documents\Visual Studio 2017\Projects\AzureResourceGroup2\AzureResourceGroup2\bin\Debug\staging\AzureR
22:26:41 - esourceGroup2\Deploy-AzureResourceGroup.ps1:108 char:5
22:26:41 - + New-AzureRmResourceGroupDeployment -Name ((Get-ChildItem $Templat ...
22:26:41 - + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
22:26:41 - + CategoryInfo : NotSpecified: (:) [New-AzureRmResourceGroupDeployment], Exception
22:26:41 - + FullyQualifiedErrorId : Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.NewAzureResourceGroupDep
22:26:41 - loymentCmdlet
ЧтоЯ пытался
Я уже пытался смотреть на этот вопрос:
, но, похоже, он использует старый формат шаблона ARM для создания вызова DSC, и поскольку я не знакомс его помощью я не могу понять, для чего нужны дополнительные параметры.
Я также взглянул на этот вопрос:
и принятый ответ - просто используйте PsDSCAllowPlainTextPassword = $true
.Хотя это выглядит не лучшим образом, я попытался добавить следующий файл данных конфигурации:
CreateLocalUser.psd1
#
# CreateLocalUser.psd1
#
@{
AllNodes = @(
@{
NodeName = '*'
PSDscAllowPlainTextPassword = $true
}
)
}
и изменить Deploy-AzureResourceGroup.ps1
, чтобы передать эти настройки в DSCконфигурации, как показано ниже.
# Create DSC configuration archive
if (Test-Path $DSCSourceFolder) {
$DSCSourceFilePaths = @(Get-ChildItem $DSCSourceFolder -File -Filter '*.ps1' | ForEach-Object -Process {$_.FullName})
foreach ($DSCSourceFilePath in $DSCSourceFilePaths) {
$DSCArchiveFilePath = $DSCSourceFilePath.Substring(0, $DSCSourceFilePath.Length - 4) + '.zip'
$DSCConfigDataFilePath = $DSCSourceFilePath.Substring(0, $DSCSourceFilePath.Length - 4) + '.psd1'
Publish-AzureRmVMDscConfiguration $DSCSourceFilePath -OutputArchivePath $DSCArchiveFilePath -ConfigurationDataPath $DSCConfigDataFilePath -Force -Verbose
}
}
Тем не менее я не получаю никаких изменений в сообщении об ошибке при этом.
Я пытался решить эту проблему с помощью документации по Azure.из.Ссылка в сообщении об ошибке совершенно бесполезна, поскольку нет примеров того, как использовать шифрование с шаблоном ARM.В большинстве примеров показаны запущенные сценарии Powershell, а не шаблон ARM.И нигде в документации нет ни одного примера того, как извлечь пароль из хранилища ключей и передать его в файл расширения DSC из шаблона ARM.Это вообще возможно?
Обратите внимание, что я был бы рад просто использовать Visual Studio для развертывания, если бы я мог просто заставить его работать.Но я работаю над этой проблемой в течение нескольких дней и, похоже, не могу найти ни одного работающего решения.Итак, я подумал, что я хотел бы спросить здесь, прежде чем бросить полотенце и просто использовать учетную запись администратора Windows для веб-развертывания.
ОБНОВЛЕНИЕ 2018-12-21
Я заметил при запускеКоманда развертывания через Visual Studio 2017, что журнал содержит сообщение об ошибке:
20:13:43 - Build started.
20:13:43 - Project "web-app-server.deployproj" (StageArtifacts target(s)):
20:13:43 - Project "web-app-server.deployproj" (ContentFilesProjectOutputGroup target(s)):
20:13:43 - Done building project "web-app-server.deployproj".
20:13:43 - Done building project "web-app-server.deployproj".
20:13:43 - Build succeeded.
20:13:43 - Launching PowerShell script with the following command:
20:13:43 - 'F:\Projects\thepath\web-app-server\bin\Debug\staging\web-app-server\Deploy-AzureResourceGroup.ps1' -StorageAccountName 'staged<xxxxxxxxxxxxxxxxx>' -ResourceGroupName 'web-app-server' -ResourceGroupLocation 'eastus2' -TemplateFile 'F:\Projects\thepath\web-app-server\bin\Debug\staging\web-app-server\web-app-server.json' -TemplateParametersFile 'F:\Projects\thepath\web-app-server\bin\Debug\staging\web-app-server\web-app-server.parameters.json' -ArtifactStagingDirectory '.' -DSCSourceFolder '.\DSC' -UploadArtifacts
20:13:43 - Deploying template using PowerShell script failed.
20:13:43 - Tell us about your experience at https://go.microsoft.com/fwlink/?LinkId=691202
После появления сообщения об ошибке оно продолжается.Я подозреваю, что это может быть связано с использованием другого метода, и именно этот метод вызывает сбой и почему другие не видят, кто я.