GetEnumerator error whilst running my script - azure

I am trying to extract and export Azure Webapp settings using the below script
$allWebApps = Get-AzureRmWebApp
$resourceGroups = $allWebApps | Select-Object 'ResourceGroup' -Unique
foreach($r in $resourceGroups)
{
$rgName = $r.ResourceGroup
$webApps = Get-AzureRmWebApp -ResourceGroupName $rgName
foreach($w in $webApps)
{
$webAppName = $w.Name
Write-Host Processing Webapp : $webAppName
$webApp = Get-AzureRmWebApp -ResourceGroupName $rgName -Name $webAppName
$appSettings = $webApps.SiteConfig.AppSettings
# Extract AppSettings to CSV
$appSettings.GetEnumerator() |
Sort-Object -Property Name -Descending |
Select-Object -Property #{n='Key';e={$_.Name}},Value |
Export-Csv -Path "C:\Cloud\$webAppName.csv" -NoTypeInformation -Append
}
}
but I keep getting the below error:
You cannot call a method on a null-valued expression.
At C:\Cloud\ExportsWebApp_config.ps1:17 char:9
+ $appSettings.GetEnumerator() |
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
can someone please assist?

$appSettings = $webApps.SiteConfig.AppSettings
I think this line should be changed, otherwise you're trying to get the properties of the entire array of web apps.
$appSettings = $webApp.SiteConfig.AppSettings

Related

How to add tags on specific Resourcegroups?

I need to add tags on only the ResourceGroups (which I don't know the name of) where a Keyvault is in. It is possible that there are more than one Keyvaults in several Resourcegroups.
This is how I tried:
Set-AzContext -Subscription $subscriptionID
#Add Currentdate on resourcegroup of Keyvault
$CurrentDate = ((Get-Date).ToString('dd-MM-yyyy'))
$Tags = #{'Date' = $Currentdate}
$Resources = (Get-AzKeyVault).ResourceGroupName
Foreach ($Resource in $Resources){
$ResourcegroupName = (Get-AzKeyVault).ResourceGroupName
$ResourcegroupId = (Get-AzResourceGroup -Name $ResourcegroupName).ResourceId
New-AzTag -ResourceId $ResourcegroupId -Tag $Tags
}
The commands work separately but in this context it gives multiple errors (below error 3 times). Getting the ResourceId gives by what I can see the main error:
Get-AzResourceGroup : Cannot convert 'System.Object[]' to the type 'System.String' required by parameter 'Name'. Specified method is not supported.
At line:11 char:47
+ ... sourcegroupId = (Get-AzResourceGroup -Name $ResourcegroupName).Resour ...
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-AzResourceGroup], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgument,Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.GetAzureResourceGroupCmdlet
New-AzTag : Cannot validate argument on parameter 'ResourceId'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At line:12 char:27
+ New-AzTag -ResourceId $ResourcegroupId -Tag $Tags
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [New-AzTag], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.Azure.Commands.Tags.Tag.NewAzureTagCommand
Thanks a lot for your help!
I understand that you need to add tags on only the ResourceGroups where a Keyvault is in.
I modified a bit your code:
Set-AzContext -Subscription $subscriptionID
#Add Currentdate on resourcegroup of Keyvault
$CurrentDate = ((Get-Date).ToString('dd-MM-yyyy'))
$Tags = #{'Date' = $Currentdate}
$Resources = (Get-AzKeyVault).ResourceGroupName
Foreach ($Resource in $Resources){
$ResourcegroupId = (Get-AzResourceGroup -Name $Resource).ResourceId
New-AzTag -ResourceId $ResourcegroupId -Tag $Tags
}

Set-AzVMCustomScriptExtension in catch?

Attempting to add an extension when not detected but keep failing to find the secret sauce to get this to work. Mind you I am a BASH guy and this is a first foray into PowerShell..
#requires -version 2
# Required parameter $subscription: name of the subscription to enable Custom Script Extensions in
param (
# NOTE: See below for reason...
# [Parameter(Mandatory = $true)] [String] $subscription
# NOTE: Prompting is great for using the script interactively, but if this will also be executed
# from a build server or ...
# NOTE: Once the parameter is marked as mandatory PowerShell it will prompt for value. That said,
# if you remove the mandatory attribute then you can set a default value as a T_THROW ...
# NOTE: This _does_ contain shortcomings if this will be used as a pipeline param ...
# https://stackoverflow.com/questions/33600279/is-it-possible-to-force-powershell-script-to-throw-if-a-required-pipeline-para
[Parameter()]
[ValidateNotNullOrEmpty()]
[String]$SubscriptionName=$(Throw "`SubscriptionName` is mandatory, please provide a value...")
)
# Connect to the current Azure account
Write-Output "Pulling Azure account credentials..."
Start-Process "https://microsoft.com/devicelogin" # steals focus...
# Login to Azure account
Connect-AzAccount
# Set the active subscription
$null = Get-AzSubscription -SubscriptionName "$SubscriptionName" |Set-AzContext
# TODO: error handling
$vms = Get-AzVM
$cseName = "VulnerabilityManagementTools"
ForEach ($vm in $vms) {
try {
$cseStatus = Get-AzVMCustomScriptExtension `
-ResourceGroupName $vm.ResourceGroupName `
-VMName $vm.Name `
-Name $cseName `
-Status
}
catch {
Write-Output "Enabling Custom Script Extension for $vm."
Set-AzVMCustomScriptExtension `
-ResourceGroupName $vm.ResourceGroup `
-Location $vm.Location `
-VMName $vm.Name `
-Name $cseName `
-TypeHandlerVersion "1.1" `
-StorageAccountName "VulnerabilityManagementTools" `
-FileName "VulnerabilityManagementInstaller.ps1" `
-ContainerName "VulnerabilityManagementTools"
}
}
End up err'ing out with
PS /.../automation-scripts> ./EnableCustomScriptExtension.ps1 SubscriptionName
Pulling Azure account credentials...
WARNING: To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code XXXXXX to authenticate.
Account SubscriptionName TenantId Environment
------- ---------------- -------- -----------
XXXX#analytics.com SubName XXXXXX-XXXX AzureCloud
Get-AzVMCustomScriptExtension : The Resource 'Microsoft.Compute/virtualMachines/XXXX/extensions/VulnerabilityManagementTools' under resource group '{NAME}' was not found.
ErrorCode: ResourceNotFound
ErrorMessage: The Resource 'Microsoft.Compute/virtualMachines/XXXX/extensions/VulnerabilityManagementTools' under resource group '{NAME}' was not found.
ErrorTarget:
StatusCode: 404
ReasonPhrase: Not Found
At /.../automation-scripts/EnableCustomScriptExtension.ps1:59 char:18
+ $cseStatus = Get-AzVMCustomScriptExtension `
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Get-AzVMCustomScriptExtension], ComputeCloudException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Compute.GetAzureVMCustomScriptExtensionCommand
Get-AzVMCustomScriptExtension : The Resource 'Microsoft.Compute/virtualMachines/XXXXX/extensions/VulnerabilityManagementTools' under resource group '{RESOURCE_GROUPNAME}' was not found.
ErrorCode: ResourceNotFound
ErrorMessage: The Resource 'Microsoft.Compute/virtualMachines/XXXX/extensions/VulnerabilityManagementTools' under resource group '{RESOURCE_GROUPNAME}' was not found.
ErrorTarget:
StatusCode: 404
ReasonPhrase: Not Found
At /.../automation-scripts/EnableCustomScriptExtension.ps1:59 char:18
+ $cseStatus = Get-AzVMCustomScriptExtension `
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Get-AzVMCustomScriptExtension], ComputeCloudException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Compute.GetAzureVMCustomScriptExtensionCommand
Get-AzVMCustomScriptExtension : The Resource 'Microsoft.Compute/virtualMachines/{VMName}/extensions/VulnerabilityManagementTools' under resource group '{RESOURCEX_GROUPNAME}' was not found.
ErrorCode: ResourceNotFound
ErrorMessage: The Resource 'Microsoft.Compute/virtualMachines/{VMName}/extensions/VulnerabilityManagementTools' under resource group '{RESOURCEX_GROUPNAME}' was not found.
ErrorTarget:
StatusCode: 404
ReasonPhrase: Not Found
At /.../automation-scripts/EnableCustomScriptExtension.ps1:59 char:18
+ $cseStatus = Get-AzVMCustomScriptExtension `
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Get-AzVMCustomScriptExtension], ComputeCloudException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Compute.GetAzureVMCustomScriptExtensionCommand`
In your case, you just need to use the if(){}else{} statement, try the script as below instead of the ForEach part of yours, it works fine on my side.
ForEach ($vm in $vms) {
$cseStatus = Get-AzVMCustomScriptExtension `
-ResourceGroupName $vm.ResourceGroupName `
-VMName $vm.Name `
-Name $cseName `
-Status `
-ErrorAction SilentlyContinue
if ($cseStatus){
Write-Host "The extension has been set for" $vm.Name
}else{
Write-Host "Enabling Custom Script Extension for" $vm.Name
Set-AzVMCustomScriptExtension `
-ResourceGroupName $vm.ResourceGroup `
-Location $vm.Location `
-VMName $vm.Name `
-Name $cseName `
-TypeHandlerVersion "1.1" `
-StorageAccountName "VulnerabilityManagementTools" `
-FileName "VulnerabilityManagementInstaller.ps1" `
-ContainerName "VulnerabilityManagementTools"
}
}
Test result:
You'll need to create an Azure AD Service Principal using password authentication and use the credentials of this to pass to the Connect-AzAccount cmdlet as follows:
$credentials = Get-Credential
Connect-AzAccount -ServicePrincipal -Credentials $credentials
The service account will need to have the necessary permissions to use the Set-AzVMCustomScriptExtensions cmdlet.
More information on creating the service account here:
https://learn.microsoft.com/en-us/powershell/azure/create-azure-service-principal-azureps?view=azps-2.8.0

Why isn't VScode pwsh terminal able to see my azure resource groups?

I'm trying to tag all my running VMs from azure with tags from a CSV file but my PowerShell script is failing when being run from VSCode PowerShell core terminal.
I double-checked and I have set the correct active subscription (we have multiple tenants and subscriptions), but the output says that it can't find my resource groups (they are there for sure).
Enable-AzureRmAlias
$csv = import-csv "C:\Users\popes\Desktop\Jedox\Powershell scripts\Tagging\Tagging.csv"
$csv | ForEach-Object {
# Retrieve existing tags
$tags = (Get-AzResource -ResourceGroupName $_.RG -ResourceType "Microsoft.Compute/virtualMachines" -Name $_.VM).Tags
# Define new value pairs from CSV
$newTags = #{
company = $_.Company
dns = $_.DNS
type = $_.Type
CN = $_.CN
}
# Add new tags to existing set (overwrite conflicting tag names)
foreach($CN in $newTags.Keys){
$tags[$_] = $newTags[$_]
}
# Update resource with new tag set
Set-AzResource -ResourceGroupName $_.RG -Name $_.VM -Tag $tags -ResourceType "Microsoft.Compute/virtualMachines"
}
The output:
Get-AzResource : Resource group 'machine774_rg' could not be found.
At line:3 char:14
+ ... $tags = (Get-AzResource -ResourceGroupName $_.RG -ResourceType "Mi ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Get-AzResource], CloudException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.GetAzureResourceCmdlet
Cannot index into a null array.
At line:15 char:9
+ $tags[$_] = $newTags[$_]
+ ~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : NullArray
Try to use Clear-AzContext, then login with specific tenant and subscription, Connect-AzAccount -Tenant "xxxx-xxxx-xxxx-xxxx" -SubscriptionId "yyyy-yyyy-yyyy-yyyy".

Problem with PSCustomObject data collection

I'm preparing a table with information about VM name and provision date of OS disk. I can easily retrieve that information from $VM.disks.statuses.time[0] command, if individual VM is assigned to $VM, but I when i try to collect data into table, I got an error:
Cannot index into a null array.
At line:4 char:1
+ [PSCustomObject]#{
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : NullArray
This is my code:
$VMs = Get-AzVM -status
$vmOutput = $VMs | ForEach-Object {
[PSCustomObject]#{
"VM Name" = $_.Name
"Provision Date" = $_.disks.statuses.time[0].ToString()
}
}
I can reproduce your issue, the issue was caused by the outputs of Get-AzVM -status and Get-AzVM -ResourceGroupName <ResourceGroupName> -Name <Name> -Status are different.
The output of Get-AzVM -status will not has the disks property, but when you get individual VM status via Get-AzVM -ResourceGroupName <ResourceGroupName> -Name <Name> -Status, it will have the property, so you got the error.
Get-AzVM -status:
Get-AzVM -ResourceGroupName <ResourceGroupName> -Name <Name> -Status:
Solution:
To fix the issue, just to use Get-AzVM -ResourceGroupName <ResourceGroupName> -Name <Name> -Status in your script.
$VMs = Get-AzVM -status
$vmOutput = $VMs | ForEach-Object {
$VMstatus = Get-AzVM -ResourceGroupName $_.ResourceGroupName -Name $_.Name -Status
[PSCustomObject]#{
"VM Name" = $VMstatus.Name
"Provision Date" = $VMstatus.disks.statuses.time[0].ToString()
}
}
You can use the Get-AzDisk command to retrieve disk creation information.
$disks = Get-AzDisk | Where-Object { $_.Managedby }
$vmOutput = foreach ($disk in $disks) {
[pscustomobject]#{"VM Name" = ($disk.ManagedBy -split "/")[-1]
"Provisioned Date" = $disk.TimeCreated
}
}
The error says:
Cannot index into a null array.
So my guess is that something here $_.disks.statuses.time[0].ToString() is $null. Therefore you should add some $nullchecks:
$VMs = Get-AzVM -status
$vmOutput = $VMs | ForEach-Object {
if ($_.disks -and $_.disks.statuses -and $_.disks.statuses.time -and ($_.disks.statuses.time.Count -gt 0)){
[PSCustomObject]#{
"VM Name" = $_.Name
"Provision Date" = $_.disks.statuses.time[0].ToString()
}
}
}
Hope that helps.

Set-AzureRmResourceGroup : 'resourceGroupName' does not match expected pattern '^[-\w\._\(\)]+$'

Running this below and can't seem to get the collection correct to pass into the ForEach loop, even though it returns the names I want.
$RGInfo returns as expected. But when I pass it into the loop to Set-AzureRmResourceGroup, it errors as below
PS H:\> $rginfo
ResourceGroupName
-----------------
rg-crp-d365-bp-n
rg-crp-d365-dev1-n
rg-crp-d365-dev2-n
rg-crp-d365-upgrad-n
$RGInfo = Get-AzureRmResourceGroup | Where-Object {$_.ResourceGroupName -like "RG-CRP-D365*" } | Select-Object ResourceGroupName
ForEach ($RGName in $RGInfo) {
If ($RGName.Tags -eq $null) {
Set-AzureRmResourceGroup -ResourceGroupName $RGName -Tag #{BUSINESS_UNIT="CRP"; COST_CENTER="6435" }
}
}
Know why I keep getting the below? There are four RG's so the ForEach loop is functional.
Set-AzureRmResourceGroup : 'resourceGroupName' does not match expected
pattern '^[-\w._()]+$'. At line:7 char:2
+ Set-AzureRmResourceGroup -ResourceGroupName $RGName -Tag #{BUSINESS_ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Set-AzureRmResourceGroup], ValidationException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.SetA
zureResourceGroupCmdlet Set-AzureRmResourceGroup :
'resourceGroupName' does not match expected pattern '^[-\w._()]+$'.
At line:7 char:2
+ Set-AzureRmResourceGroup -ResourceGroupName $RGName -Tag #{BUSINESS_ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Set-AzureRmResourceGroup], ValidationException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.SetA
zureResourceGroupCmdlet Set-AzureRmResourceGroup :
'resourceGroupName' does not match expected pattern '^[-\w._()]+$'.
At line:7 char:2
+ Set-AzureRmResourceGroup -ResourceGroupName $RGName -Tag #{BUSINESS_ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Set-AzureRmResourceGroup], ValidationException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.SetA
zureResourceGroupCmdlet Set-AzureRmResourceGroup :
'resourceGroupName' does not match expected pattern '^[-\w._()]+$'.
At line:7 char:2
+ Set-AzureRmResourceGroup -ResourceGroupName $RGName -Tag #{BUSINESS_ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Set-AzureRmResourceGroup], ValidationException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.SetA
zureResourceGroupCmdlet
First you filtered the content of $RGInfo to only the Resource Group name, you cannot add tags to just the name
$RGInfo = Get-AzureRmResourceGroup | Where-Object {$_.ResourceGroupName -like "RG-CRP-D365*" } | Select-Object ResourceGroupName
Below syntax should work.
$RGInfo = Get-AzureRmResourceGroup | Where-Object {$_.ResourceGroupName -like "RG-CRP-D365*" }
ForEach ($RGName in $RGInfo)
{
If ($RGName.Tags -eq $null)
{
Set-AzureRmResourceGroup -ResourceGroupName $RGName.ResourceGroupName -Tag #{BUSINESS_UNIT="CRP"; COST_CENTER="6435" }
}
}
Hope this helps.
I had a similar issue when importing a list from a CSV file. Turns out the RG names had spaces on it 🤦‍♂️.

Resources