Smarter than CoPilot

Smarter than CoPilot

While writing code in, for example, PowerShell, you occasionally use help from CoPilot. When an inexplicable error message appears, you turn to CoPilot again for assistance. CoPilot then literally and figuratively analyzes its own code. Miraculously, there’s always something that can be improved. Fortunately, humans are still smarter than CoPilot. Take this piece of code, for example, to add a client secret to an Azure AD app registration.

Function Add-AzureAdSecret {

    # Check for existing application and create secret if necessary
    try {
        $app = Get-MgApplication -Filter "displayName eq '$appName'"
        if (-not $app) {
            Write-Host "App registration does not exist. Skipping creation of secret."
        } else {
            Write-Host "App registration exists. Creating secret."

            $passwordCredential = @{
                displayName = $secretDisplayName
                startDateTime = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ssZ")
                endDateTime = (Get-Date).AddYears(2).ToString("yyyy-MM-ddTHH:mm:ssZ")
            }

            # Add the password credential to the application
            $newPassword = Add-MgApplicationPassword -ApplicationId $app.Id -PasswordCredential $passwordCredential
            $appSecret = $newPassword.SecretText

            # Update environment variables based on keys in the hashtable
            if ($variables.ContainsKey('Crm:ClientId') -and $variables.ContainsKey('Crm:ClientSecret')) {
                $azureAdParameters = @{
                    'Crm:ClientId' = $app.AppId
                    'Crm:ClientSecret' = $appSecret
                }
            } elseif ($variables.ContainsKey('CrmClientId') -and $variables.ContainsKey('CrmClientSecret')) {
                $azureAdParameters = @{
                    'CrmClientId' = $app.AppId
                    'CrmClientSecret' = $appSecret
                }
            } else {
                Write-Host "No matching environment variable keys found. Skipping environment variable update."
                return
            }

            Write-Host "Generated Client Secret: $appSecret. Now updating environment variables"
            $redirect = (Update-AzFunctionAppSetting -Name $azureFunctionName -ResourceGroupName $resourceGroup -AppSetting $azureAdParameters) 2>$null
            Write-Host "Updated the Azure function with a client secret of two years"
        }
    } catch {
        Write-Error "Failed to create or retrieve the application or secret. Error details: $_"
    }
}
# End Function Add-AzureAdSecret    } catch {
        Write-Error "Failed to create or retrieve the application or secret. Error details: $_"
    }
}

Not smarter than Copilot after all?

It seems like the script is encountering issues when adding the client secret via script. Here are a few potential reasons and solutions:

Error Handling: Enhance the error handling in the script to capture more detailed error messages. This can help identify the exact point of failure.

Timing Issue: There might be a delay in the propagation of the new secret. Try adding a short delay after creating the secret before using it in the subsequent steps.

Permissions: Ensure that the script has the necessary permissions to create and update secrets. Verify the role assignments and permissions for the service principal.

Environment Variables Update: The script might not be updating the environment variables correctly. Double-check the logic for updating the environment variables and ensure they are being set properly.

Start-Sleep -Seconds 10  # Adding delay

Then another new response

Unfortunately, I can’t directly verify which secret is correct or incorrect based on the values provided. However, here are some steps you can take to troubleshoot:

  1. Check for Typographical Errors: Ensure there are no typos or extra spaces in the secret values.
  2. Expiration: Verify that the secret hasn’t expired. You can check the expiration date in the Azure portal.
  3. Permissions: Ensure the secret has the necessary permissions to access the resources.
  4. Consistency: Make sure the secret is correctly set in the environment variables and matches the one in Azure AD.

If you manually change the secret and it works, it might be worth regenerating the secret and updating your script with the new value. This often resolves unexpected issues.

My response to CoPilot
The first two were created via script, while the others are created manually via the portal.

t3D8Q~v9c5arpv.tuV_UXx7Cx-GlFCe2yFKE-d
eW9lM8Q~Wvb1uTi0bnTyVxjeFPkkRg62.Uw
Xox8Q~QmKph~Lmwhwt6LcDXjplEZInVD4YBErcyg
Uqa8Q~Fdr.qwV6-VC5w9~F3VqA4WQ3_IeyqqhccL

Could it be that the following code generates wrong secrets (CoPilot hadn’t thought of that yet — and luckily, humans are still just a bit smarter than CoPilot.)

$passwordCredential = @{
                displayName = $secretDisplayName
                startDateTime = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ssZ")
                endDateTime = (Get-Date).AddYears(2).ToString("yyyy-MM-ddTHH:mm:ssZ")
            }

            $newPassword = Add-MgApplicationPassword -ApplicationId $app.Id -PasswordCredential $passwordCredential
            $appSecret = $newPassword.SecretText

Another response from CoPilot

It seems like the issue might be related to how the secrets are generated via the script. Here are a few things to consider:

  • Propagation Delay: There might be a delay in the propagation of the new secret. Adding a short delay after creating the secret might help.
  • Date Format: Ensure that the date format used in the script is correct and matches the expected format. The ToString("yyyy-MM-ddTHH:mm:ssZ") format should be fine, but it’s worth double-checking.
  • Permissions: Verify that the script has the necessary permissions to create and update secrets. The service principal running the script should have the Application.ReadWrite.All or Directory.ReadWrite.All permissions.
  • Secret Length and Complexity: Sometimes, the generated secrets might not meet the complexity requirements. Ensure that the secrets generated by the script are sufficiently complex.

My question was how to analyze the date format. According to CoPilot, that could be done using a new script.

Yes, you can verify the expiration date and time of the client secret using the Azure AD Graph API. Here’s how you can do it:

  1. Retrieve Application Details: Use the Get-MgApplication cmdlet to retrieve the details of the application, including the passwordCredentials property which contains the expiration date.
  2. Check Expiration Date: Inspect the endDateTime property of the passwordCredentials to verify the expiration date and time.

Here’s a sample script to help you verify the expiration date and time:

# Connect to Microsoft Graph
Connect-MgGraph -TenantId $TenantId -Scopes "User.Read","Application.ReadWrite.All","Directory.ReadWrite.All" -NoWelcome

# Retrieve application details
$app = Get-MgApplication -Filter "displayName eq '$appName'"

# Check expiration date of client secrets
foreach ($credential in $app.passwordCredentials) {
    Write-Host "Secret Display Name: $credential.displayName"
    Write-Host "Start Date: $credential.startDateTime"
    Write-Host "End Date: $credential.endDateTime"
}

The date format was perfect according to the output.

However, CoPilot didn’t give up

Your code for setting the endDateTime looks correct. It uses the AddYears method to add two years to the current date and formats it in the ISO 8601 format (yyyy-MM-ddTHH:mm:ssZ). This should work as expected.

Smarter than CoPilot

In the end, this was the solution:

$passwordCredential = @{
displayName = $secretDisplayName
startDateTime = (Get-Date)
endDateTime = (Get-Date).AddYears(2)
}

More information about Add-MgApplicationPassword can be found on the Microsoft site. Information about the author can be found on the Digitale Mels website.

Happy Scripting 🙂

0 Shares:
You May Also Like