访问 Azure Key Vault 机密时脚本在 Windows 10 中挂起,在 Windows 11 中运行:需要帮助

问题描述 投票:0回答:1

我正在编写一个脚本,它从 Azure Key Vault 获取机密的详细信息,并将机密重新创建到不同租户的另一个 Key Vault 中。我使用 Windows 窗体提供 GUI 来选择所需的机密。 该脚本在 Windows 11 中运行良好,但在 Windows 10 中尝试执行时,脚本有时会卡住。它似乎挂在 Get-AzKeyvaultSecret cmdlet 的第 183 行处。这个问题偶尔会发生,我不明白为什么会发生。 以下是 PowerShell 版本:

  1. Windows 10: PowerShell 版本:5.1.19041.3031

  2. Windows 11: PowerShell版本:5.1.22621.2506

任何帮助将不胜感激。 截屏:

代码:

    # Load Windows Forms
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

# Load configuration from JSON file
Try {
    $configFilePath = "D:\AxKVMigrationInfo\config.json"
    $config = Get-Content $configFilePath -ErrorAction Stop | ConvertFrom-Json 
}
Catch {
    Write-Host "[ERROR] Config file not found: $_"
    exit 1
}

# Set log file path from the configuration
$logFilePath = $config.FilePaths.Log

# Subscription details for Source Tenant
$sourceSubscriptionId = $config.SourceTenant.SubscriptionId
$sourceVaultName = $config.SourceTenant.VaultName

# Subscription details for Target Tenant
$targetSubscriptionId = $config.TargetTenant.SubscriptionId
$targetVaultName = $config.TargetTenant.VaultName

# CSV file path where migrated secrets will get exported
$logDirectory = Split-Path -Path $LogFilePath -Parent
$CSVFilePath = Join-Path -Path $logDirectory -ChildPath "Migrated_Secrets.csv"


# Function to log messages
function Write-Log {
    param (
        [string]$message,
        [string]$logType
    )

    $logMessage = "$logType - $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - $message"
    Add-Content -Path $logFilePath -Value $logMessage
}

# Function to check and install requried modules
function Import-RequiredModule {
    Try {
        Import-Module -Name Az.KeyVault -ErrorAction Stop
        Import-Module -Name Az.Accounts -ErrorAction Stop
    }
    catch { 
        Write-Host "The required PowerShell module is not found on the machine. Installing the modules Az.KeyVault and Az.Accounts." 
        Write-Log "The required PowerShell module is not found on the machine. Installing the modules Az.KeyVault and Az.Accounts." "[INFO]"

        Install-Module -Name Az.KeyVault
        Install-Module -Name Az.Accounts
        
        Import-Module -Name Az.KeyVault
        Import-Module -Name Az.Accounts
        Write-Host "Az.KeyVault and Az.Accounts successfully installed and imported" 
        Write-Log "Az.KeyVault and Az.Accounts successfully installed and imported" "[INFO]"
    }
}

# Function to prompt the user to enter tenant credentials
function Prompt-ForCredentials {
    param (
        [string]$account
    )

    $title = "Enter $account Tenant Credentials"
    $message = "Please enter the credentials for $account Tenant."

    [System.Windows.Forms.MessageBox]::Show($message, $title, [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
}


# Function to connect to Azure account and log connection event
function Connect-ToAzureAccount {
    param (
        [string]$SubscriptionId,
        [string]$Account
    )

    Write-Host "Enter $Account Tenant credentials"
    # Prompt user for credentials
    Prompt-ForCredentials -account $Account

    # Connect to Azure account
    try {
        Connect-AzAccount -Subscription $SubscriptionId -ErrorAction Stop
        
        # Get the current user
        $currentUser = (Get-AzContext).Account.Id
        Write-Log "Connected to $Account Azure account. User: $currentUser" "[INFO]"
    }
    catch {
        Write-Log "Error connecting to $Account Azure account: $_" "[ERROR]"
        throw "Error connecting to $Account Azure account."
    }
}

# Function to disconnect from Azure account and log disconnection event
function Disconnect-FromAzureAccount {
    param (
        [string]$Account
    )

    # Disconnect from Azure account
    try {
        Disconnect-AzAccount -ErrorAction Stop
        Write-Log "Disconnected from $Account Azure account" "[INFO]"
    }
    catch {
        Write-Log "Error disconnecting from $Account Azure account: $_" "[ERROR]"
        throw "Error disconnecting from $Account Azure account."
    }
}

# Function to display a confirmation message box
function Show-ConfirmationBox {
    param (
        [string]$message
    )

    return [System.Windows.Forms.MessageBox]::Show(
        $message,
        "Confirmation",
        [System.Windows.Forms.MessageBoxButtons]::OKCancel,
        [System.Windows.Forms.MessageBoxIcon]::Warning
    )
}


# Function to export specific secrets from source Key Vault based on CSV file
function Export-SpecificSecretsFromSourceKeyVault {
    param (
        [string]$SourceVaultName,
        [string]$SourceSubscriptionId,
        [string[]]$ArrSelectedSecretName
    )

    # Update the minimum and maximum of the progress bar.
    $ProgressBar.Minimum = 0
    $ProgressBar.Maximum = $ArrSelectedSecretName.Count

    # Update the text of the Progress label.
    $progressLable.Text = "Exporting....."

    Write-Host "Exporting specific secrets from source Key Vault ($SourceVaultName) in Subscription ($SourceSubscriptionId)"
    Write-Log "Exporting specific secrets from source Key Vault ($SourceVaultName) in Subscription ($SourceSubscriptionId)" "[INFO]"

    # Export specific secrets based on Selected Items
    $SpecificSecretDetailsExport = foreach ($secretName in $ArrSelectedSecretName) {
        
        # update progress status:
        $ProgressBar.Value = $ProgressBarValue
        
        try {
            Get-AzKeyVaultSecret -VaultName $SourceVaultName -Name $secretName -ErrorAction Stop
        }
        catch {
            Write-Log "Error exporting secret '$secretName' from source Key Vault: $_" "[ERROR]"
        }
        $ProgressBarValue++
    }

    # Update the text of the Progress label.
    $progressLable.Text = "Exported"

    Write-Host "Exporting Successful."
    Write-Log "Exporting Successful." "[INFO]"

    Disconnect-FromAzureAccount -Account "Source"

    return $SpecificSecretDetailsExport
}


# Function to export migrated or imported secrets to CSV
function Export-SecretsToCSV {
    param (
        [string]$CSVFilePath,
        [PSCustomObject]$SecretDetail
    )

    # Extract specific details for each secret
    $exportData = [PSCustomObject]@{
        SecretName     = $SecretDetail.Name
        ContentType    = $SecretDetail.ContentType
        ActivationDate = $SecretDetail.NotBefore
        ExpiryDate     = $SecretDetail.Expires
        State          = $SecretDetail.Enabled
    }

    $exportData | Export-Csv -Path $CSVFilePath -NoTypeInformation -Append
    Write-Log "Secrets exported to CSV file: $CSVFilePath" "[INFO]"
}



# Function to import secrets into target Key Vault
function Import-SecretsIntoTargetKeyVault {
    param (
        [string]$TargetVaultName,
        [string]$TargetSubscriptionId,
        [Array]$SecretDetails
    )

    Connect-ToAzureAccount -SubscriptionId $TargetSubscriptionId -Account "Target"

    # Update the minimum and maximum of the progress bar.
    $ProgressBar.Minimum = 0
    $ProgressBar.Maximum = $SecretDetails.Count

    # Update the text of the Progress label.
    $progressLable.Text = "Importing....."

    Write-Log "Importing secrets into target Key Vault ($TargetVaultName) in Subscription ($TargetSubscriptionId)." "[INFO]"

    # Core logic
    foreach ($SD in $SecretDetails) {
        $SecretName = $SD.Name

        # update progress status:
        $ProgressBar.Value = $ProgressBarValue

        if ($SecretName -ne $null) {
            # Check if the secret already exists in the target Key Vault
            $existingSecret = Get-AzKeyVaultSecret -VaultName $TargetVaultName -Name $SecretName -ErrorAction SilentlyContinue
            if ($existingSecret -eq $null) {
                # Create secret into the Target Tenant
                try {
                    Set-AzKeyVaultSecret -VaultName $TargetVaultName -Name $SecretName -SecretValue $SD.SecretValue -Expires $SD.Expires -NotBefore $SD.NotBefore -ContentType $SD.ContentType -Tag $SD.Tags -ErrorAction Stop
                    
                    Write-Log "Secret '$SecretName' imported successfully." "[SUCCESS]"

                    # Call Export-SecretsToCSV function after importing secrets into the target Key Vault
                    Export-SecretsToCSV -CSVFilePath $CSVFilePath -SecretDetail $SD
                    
                }
                catch {
                    Write-Log "Error importing secret '$SecretName' into target Key Vault: $_" "[ERROR]"
                }
            }
            else {
                Write-Log "Secret '$SecretName' already exists in the target Key Vault. Skipping." "[WARNING]"
            }
        }
    
        $ProgressBarValue++
    
    }

    # Update the text of the Progress label.
    $progressLable.Text = "Imported"

    Disconnect-FromAzureAccount -Account "Target"

    Write-Log "Import completed successfully." "[INFO]"
}


# Define minimum form size
$minimumFormSize = New-Object System.Drawing.Size(500, 550)

# Function to dynamically adjust the size of $checkedListBox based on form size
function Resize-CheckedListBox {
    $checkedListBox.Size = New-Object System.Drawing.Size(($form.ClientSize.Width - 30), ($form.ClientSize.Height - 150))
    $buttonSelectAll.Location = New-Object System.Drawing.Point(10, ($form.ClientSize.Height - 120))
    $buttonDeselectAll.Location = New-Object System.Drawing.Point(170, ($form.ClientSize.Height - 120))
    $buttonMigrate.Location = New-Object System.Drawing.Point(($form.ClientSize.Width - $buttonMigrate.Width - 30), ($form.ClientSize.Height - 120))
    $progressBar.Location = New-Object System.Drawing.Point(10, ($form.ClientSize.Height - 60))
    $progressLable.Location = New-Object System.Drawing.Point(350, ($form.ClientSize.Height - 60))
}

# Function to enforce minimum form size
function Enforce-MinimumFormSize {
    if ($form.ClientSize.Width -lt $minimumFormSize.Width -or $form.ClientSize.Height -lt $minimumFormSize.Height) {
        $form.ClientSize = $minimumFormSize
    }
}

# Function to enable or disable the migration button based on selection
function Update-MigrationButton {
    if ($checkedListBox.CheckedItems.Count -gt 0) {
        $buttonMigrate.Enabled = $true
    }
    else {
        $buttonMigrate.Enabled = $false
    }
}

# Create Form
$form = New-Object System.Windows.Forms.Form
$form.Text = "AzKV Secret Migration Tool"
$form.Size = $minimumFormSize  # Set initial form size to minimum
$form.StartPosition = "CenterScreen"

# Attach Resize event handler to form
$form.add_Resize({
        Resize-CheckedListBox
        Enforce-MinimumFormSize
    })

# Attach Load event handler to form to ensure minimum size is enforced initially
$form.add_Load({
        Enforce-MinimumFormSize
    })

# Create CheckedListBox
$checkedListBox = New-Object System.Windows.Forms.CheckedListBox
$checkedListBox.Location = New-Object System.Drawing.Point(10, 10)
$checkedListBox.Font = New-Object System.Drawing.Font("Arial", 12)  # Adjust the font size as needed
$checkedListBox.ItemHeight = 30  # Adjust the height as needed

# Create Button for Select All
$buttonSelectAll = New-Object System.Windows.Forms.Button
$buttonSelectAll.Size = New-Object System.Drawing.Size(150, 30)
$buttonSelectAll.Location = New-Object System.Drawing.Point(10, ($form.ClientSize.Height - 120))
$buttonSelectAll.Text = "Select All"

# Add Click event to the Select All Button
$buttonSelectAll.Add_Click({
        # Check all checkboxes
        for ($i = 0; $i -lt $checkedListBox.Items.Count; $i++) {
            $checkedListBox.SetItemChecked($i, $true)

            # Update migration button status
            Update-MigrationButton
        }
    })

# Create Button for Deselect All
$buttonDeselectAll = New-Object System.Windows.Forms.Button
$buttonDeselectAll.Size = New-Object System.Drawing.Size(150, 30)
$buttonDeselectAll.Location = New-Object System.Drawing.Point(170, ($form.ClientSize.Height - 120))
$buttonDeselectAll.Text = "Deselect All"

# Add Click event to the Deselect All Button
$buttonDeselectAll.Add_Click({
        # Uncheck all checkboxes
        for ($i = 0; $i -lt $checkedListBox.Items.Count; $i++) {
            $checkedListBox.SetItemChecked($i, $false)

            # Update migration button status
            Update-MigrationButton
        }
    })

# Create Button for Migrate
$buttonMigrate = New-Object System.Windows.Forms.Button
$buttonMigrate.Size = New-Object System.Drawing.Size(150, 30)
$buttonMigrate.Text = "Migrate Secrets"
$buttonMigrate.Enabled = $false  # Initially disable the button


# Import required Module
Import-RequiredModule


# Get secrets from source Key Vault
Connect-ToAzureAccount -SubscriptionId $SourceSubscriptionId -Account "Source"
Try {
    $secrets = Get-AzKeyVaultSecret -VaultName $sourceVaultName
}
catch {
    Write-Log "Error Listing secret '$secretName' from source Key Vault: $_" "[ERROR]"
    exit 1
}


# Populate CheckedListBox with secret names
$secrets | ForEach-Object {
    [void]$checkedListBox.Items.Add($_.Name)
}

# Progress Bar
$progressBar = New-Object System.Windows.Forms.ProgressBar
$progressBar.Style = "Continuous"
$progressBar.Width = 310
$progressBar.Height = 25
$progressBar.Location = New-Object System.Drawing.Point(10, ($form.ClientSize.Height - 60))
$ProgressBarValue = 1

# Progress bar label
$progressLable = New-Object System.Windows.Forms.Label
$progressLable.AutoSize = $true
$progressLable.Width = 100
$progressLable.Height = 25
$progressLable.Location = New-Object System.Drawing.Point(350, ($form.ClientSize.Height - 60))




# Add Click event to the Button
$buttonMigrate.Add_Click({
        # Display confirmation message box
        $confirmation = Show-ConfirmationBox "The selected secrets will be Imported into the target tenant. If you want to migrate click on OK"
        

        # Check if the user clicked OK
        if ($confirmation -eq [System.Windows.Forms.DialogResult]::OK) {
            # Get selected secrets
            $selectedSecrets = Export-SpecificSecretsFromSourceKeyVault -SourceVaultName $sourceVaultName -SourceSubscriptionId $sourceSubscriptionId -ArrSelectedSecretName $checkedListBox.CheckedItems
            
            # Proceed with migration
            Import-SecretsIntoTargetKeyVault -TargetVaultName $targetVaultName -TargetSubscriptionId $targetSubscriptionId -SecretDetails $selectedSecrets
            
            # Show Import successful message
            [System.Windows.Forms.MessageBox]::Show("Imported successfully! For more details, check the logs file.", "Import Successful", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)

            $form.Close()
        }
        
    })


# Add controls to the form
$form.Controls.AddRange(@($checkedListBox, $buttonSelectAll, $buttonDeselectAll, $buttonMigrate, $progressBar, $progressLable))

# Add Change event to the checkedListBox to update migration button status
$checkedListBox.Add_SelectedIndexChanged({ Update-MigrationButton })

# Call Resize-CheckedListBox to set initial sizes and positions
Resize-CheckedListBox

# Show the form
[void]$form.ShowDialog()

# Display a message indicating the completion of the script
Write-Log "Key Vault migration script completed successfully." "[INFO]"

# Display the log file path
Write-Host "Log file exported to: $logFilePath"

# Display the log file path
Write-Host "CSV file exported to: $CSVFilePath"

# Remove all variables for no longer access.
Remove-Variable * -ErrorAction SilentlyContinue

我已尝试以下步骤:

  • 尝试使用不同版本的 Az.KeyVault 模块;然而,脚本仍然卡住了。
  • 尝试在从 Azure 密钥保管库获取详细信息之间添加睡眠值,但它也不起作用。
  • 在没有 GUI 的情况下测试,效果很好。

我希望该脚本能够在 Windows 10 上运行,就像它在 Windows 11 中运行一样。

azure powershell azure-keyvault
1个回答
0
投票

检查PowerShell版本和Windows 10是否兼容以执行脚本。执行

$PSVersionTable
,如下所示。

检查 keyvault 模块版本并按以下格式导入所需版本的模块以避免冲突。

Import-Module Az.KeyVault -RequiredVersion xx

enter image description here

向脚本中添加调试点,以确保并检查到底是哪里失败了。

检查代码 GUI 及其版本的依赖关系,因为它们可能会影响代码无法按预期工作。

尝试重新启动当前的 PS Session 窗口并再次执行脚本。有时重新启动窗口可以解决此类问题。

参考12了解更多相关信息。

© www.soinside.com 2019 - 2024. All rights reserved.