I was wondering if someone could help, we have some users in our organisation who are using uppercase email address, certain applications can't recognize this and fail. I have developed the script below to change the users UPN and display names to lowercase, however this doesn't change their email address. I don't want to create new mailboxes as there are several hundred users that have the incorrect format. If anyone could point me in the right direction, that would be a great help.
#Install-module AzureAD
#Connect-AzureAD
$Users = Get-azureADUser -filter "userPrincipalName eq 'User1#MyDomain.com'"
$ErrorActionPreference = 'Stop'
$OutputObj = New-Object -TypeName PSobject
$OutputObj1 = New-Object -TypeName PSobject
$SuccessOutput = #()
$ErrorOutput = #()
$Case = "toLower"
Function ChangeToLowerCase{
Try{
foreach ($user in $users) {
$user | Set-AzureADUser -userPrincipalName $user.userPrincipalName.$Case()
$user | Set-AzureADUser -identity $user.SipProxyAddress.$Case()
#$User | Select-Object DisplayName, userPrincipalName,Mail
$OutputObj | Add-Member -memberType NoteProperty -name "Display Name" -value $($user.DisplayName)
$OutputObj | Add-Member -memberType NoteProperty -name "UPN" -value $($user.userPrincipalName)
$OutputObj | Add-Member -memberType NoteProperty -name "Email Address" -value $($user.Mail)
$SuccessOutput +=$OutputObj
$SuccessOutput | Export-csv "C:\Temp\Powershell\Completed\UPN Changes.csv" -NoTypeInformation -NoClobber -Append
}
}
Catch{
$OutputObj1 | Add-Member -memberType NoteProperty -name "Display Name" -value $($user.DisplayName)
$OutputObj1 | Add-Member -memberType NoteProperty -name "Error Message" -value $($_.Exception.Message)
$ErrorOutput +=$OutputObj1
$ErrorOutput | Export-csv "C:\Temp\Powershell\Errors\UPN Changes Error.csv" -NoTypeInformation -NoClobber -Append
}
}
ChangeToLowerCase
I am looking at the Set-AzureAduser property, however I am unable to change the mail property in this variable.
Nice, I had the same issue after we added a domain with a capital W. It wont change the email address because it's not case sensitive.
I created this to resolve the issue:
function ConvertTo-LowerW
{
foreach ($Recipient in $Recipients)
{
"1"
$Recipient.PrimarySmtpAddress
$SplitEmail = $Recipient.PrimarySmtpAddress.Split('#')
$BeforeA = $SplitEmail | Select-Object -First 1
$AfterA = ($SplitEmail | Select-Object -Last 1).ToLower()
$NewPrimarySmtpAddress = $BeforeA + '#' + $AfterA
$NewPrimarySmtpAddress
switch ($Recipient.RecipientType)
{
'UserMailbox'
{
try
{
$Addresses = (Get-Mailbox -Identity $Recipient.PrimarySmtpAddress -ErrorAction Stop).EmailAddresses
$Addresses = $Addresses.Replace("SMTP:$($recipient.PrimarySmtpAddress)", "")
Set-Mailbox -ErrorAction Stop `
-Identity $Recipient.PrimarySmtpAddress `
-EmailAddresses $NewPrimarySmtpAddress
if ($Addresses.Length -ne 0)
{
foreach ($Address in ($Addresses | Where-Object { $_.Length -ne 0 }) )
{
$Address
if ($Address.Length -ne 0 )
{
Set-Mailbox -ErrorAction Stop `
-Identity $Recipient.PrimarySmtpAddress `
-EmailAddresses #{add = "$Address" }
}
}
}
}
Catch
{
$ErrorList.Add($Recipient.PrimarySmtpAddress)
$ErrorList.Add($_.Exception.Message)
}
}
'MailUniversalDistributionGroup'
{
try
{
$Addresses = (Get-DistributionGroup -Identity $Recipient.PrimarySmtpAddress -ErrorAction Stop).EmailAddresses
$Addresses = $Addresses.Replace("SMTP:$($recipient.PrimarySmtpAddress)", "")
Set-DistributionGroup -ErrorAction Stop `
-Identity $Recipient.PrimarySmtpAddress `
-EmailAddresses $NewPrimarySmtpAddress
if ($Addresses.Length -ne 0)
{
foreach ($Address in ($Addresses | Where-Object { $Addresses.Length -ne 0 }))
{
if ($Address.Length -ne 0 )
{
Set-DistributionGroup -ErrorAction Stop `
-Identity $Recipient.PrimarySmtpAddress `
-EmailAddresses #{add = "$Address" }
}
}
}
}
catch
{
$ErrorList.Add($Recipient.PrimarySmtpAddress)
$ErrorList.Add($_.Exception.Message)
}
}
'DynamicDistributionGroup'
{
try
{
$Addresses = (Get-DynamicDistributionGroup -Identity $Recipient.PrimarySmtpAddress -ErrorAction Stop).EmailAddresses
$Addresses = $Addresses.Replace("SMTP:$($recipient.PrimarySmtpAddress)", "")
Set-DynamicDistributionGroup -ErrorAction Stop `
-Identity $Recipient.PrimarySmtpAddress `
-EmailAddresses $NewPrimarySmtpAddress
if ($Addresses.Length -ne 0)
{
foreach ($Address in ($Addresses | Where-Object { $Addresses.Length -ne 0 }))
{
$Address
if ($Address.Length -ne 0 )
{
Set-DynamicDistributionGroup -ErrorAction Stop `
-Identity $Recipient.PrimarySmtpAddress `
-EmailAddresses #{add = "$Address" }
}
}
}
}
catch
{
$ErrorList.Add($Recipient.PrimarySmtpAddress)
$ErrorList.Add($_.Exception.Message)
}
}
Default
{
try
{
$Recipient.RecipientType
$Recipient.RecipientTypeDetails
'User has an unrecognized Recipienttype'
Send-Email `
-To $to `
-Body 'Test' `
-Subject 'User has an unrecognized Recipienttype'
}
catch
{
$ErrorList += "$($($Recipient).PrimarySmtpAddress) has an unrecognized RecipientType $($($Recipient).Recipienttype)"
$ErrorList.Add($Recipient.PrimarySmtpAddress)
$ErrorList.Add($_.Exception.Message)
}
}
}
}
}
I'll see if I can create a blog post on bwit.blog regarding this.
Related
I have an Azure subscription with many Service Bus queues and topics. Is there an easy way of checking the active and deadletter message counts across all queues and topic subscriptions, without clicking through them one by one?
This can be achieved by running a PowerShell script in the Azure Cloud Shell.
If all the queues and topics you're interesting in belong to one Service Bus namespace, you can use:
$resourceGroupName = <enter your resource group name here>
$namespaceName = <enter your namespace name here>
$queueMessageCounts = #()
$topicMessageCounts = #()
$queues = Get-AzServiceBusQueue -ResourceGroup $resourceGroupName -NamespaceName $namespaceName
foreach ($queue in $queues) {
$queueMessageCounts += [PSCustomObject]#{
Queue = $queue.Name
ActiveMessageCount = $queue.CountDetailActiveMessageCount
DeadLetterMessageCount = $queue.CountDetailDeadLetterMessageCount
}
}
$queueMessageCounts | Format-Table
$topics = Get-AzServiceBusTopic -ResourceGroup $resourceGroupName -NamespaceName $namespaceName
foreach ($topic in $topics) {
$subscriptions = Get-AzServiceBusSubscription -ResourceGroup $resourceGroupName -NamespaceName $namespaceName -TopicName $topic.Name
foreach ($subscription in $subscriptions) {
$topicMessageCounts += [PSCustomObject]#{
Topic = $topic.Name
Subscription = $subscription.Name
ActiveMessageCount = $subscription.CountDetailActiveMessageCount
DeadLetterMessageCount = $subscription.CountDetailDeadLetterMessageCount
}
}
}
$topicMessageCounts | Format-Table
If you want to get everything in your subscription, use:
$queueMessageCounts = #()
$topicMessageCounts = #()
$namespaces = Get-AzServiceBusNamespace
foreach ($namespace in $namespaces) {
$queues = Get-AzServiceBusQueue -ResourceGroup $namespace.ResourceGroupName -NamespaceName $namespace.Name
foreach ($queue in $queues) {
$queueMessageCounts += [PSCustomObject]#{
Namespace = $namespace.Name
Queue = $queue.Name
ActiveMessageCount = $queue.CountDetailActiveMessageCount
DeadLetterMessageCount = $queue.CountDetailDeadLetterMessageCount
}
}
$topics = Get-AzServiceBusTopic -ResourceGroup $namespace.ResourceGroupName -NamespaceName $namespace.Name
foreach ($topic in $topics) {
$subscriptions = Get-AzServiceBusSubscription -ResourceGroup $namespace.ResourceGroupName -NamespaceName $namespace.Name -TopicName $topic.Name
foreach ($subscription in $subscriptions) {
$topicMessageCounts += [PSCustomObject]#{
Namespace = $namespace.Name
Topic = $topic.Name
Subscription = $subscription.Name
ActiveMessageCount = $subscription.CountDetailActiveMessageCount
DeadLetterMessageCount = $subscription.CountDetailDeadLetterMessageCount
}
}
}
}
$queueMessageCounts | Format-Table
$topicMessageCounts | Format-Table
You can apply PowerShell commands to sort or filter the results; for example:
$queueMessageCounts | Where-Object {$_.DeadLetterMessageCount -gt 0} | Sort-Object -Property DeadLetterMessageCount -Descending | Format-Table
$topicMessageCounts | Where-Object {$_.DeadLetterMessageCount -gt 0} | Sort-Object -Property DeadLetterMessageCount -Descending | Format-Table
I tried creating a script to get all azure subnets and their details.
How to get all azure subnets including their address and associated NSG?
$list = $null
$list = #()
$vnets = Get-AzVirtualNetwork
foreach ($vnet in $vnets) {
$subnets = $vnet.Subnets.name
foreach ($subnet in $subnets){
$SubnetDetails = Get-AzVirtualNetworkSubnetConfig -Name $subnet -VirtualNetwork $vnet
$list += [PSCustomObject]#{
VNETName = $vnet.Name
VNETAddressSpaces = $vnet.AddressSpace.AddressPrefixes -join ', '
SubnetName = $SubnetDetails.name
SubnetsPrefix = $SubnetDetails.AddressPrefix -join ''
SubnetNSG = if($SubnetDetails.NetworkSecurityGroup -eq $Null) {"No NSG"} else{$SubnetDetails.NetworkSecurityGroup.id.split('/')[8]}
SubnetNSGID = if($SubnetDetails.NetworkSecurityGroup -eq $Null) {"No NSG"} else{$SubnetDetails.NetworkSecurityGroup.id}
}
}
}
$list | ogv
I am new to PowerShell and trying to get the tags for all the resources in multiple Azure subscriptions and send the output in the csv file. Below is the script, it is writing output on the screen but not in the csv file. Could anyone correct me, to export all data to csv file. Appreciate your help.
SubscriptionIds = Get-Content -Path "path for SubscriptionID.txt"
Foreach($SubscriptionId in $SubscriptionIds)
{
Try{$null = Set-AzContext -SubscriptionId $SubscriptionId}
catch [Exception] {write-host ("Error occured: " + $($_.Exception.Message)) -ForegroundColor Red;Exit}
Write-Host "Azure Login Session successful" -ForegroundColor Green -BackgroundColor Black
# Initialise output array
$Output = #()
# Collect all the groups from the current subscription
$ResourceGroups = Get-AzResourceGroup
foreach ($ResourceGroup in $ResourceGroups) {
Write-Host "Resource Group =$($ResourceGroup.ResourceGroupName)"
$resourceNames= Get-AzResource -ResourceGroupName $ResourceGroup.ResourceGroupName
$tags=Get-AzTag -ResourceId $ResourceGroup.ResourceId
foreach($key in $tags.Properties.TagsProperty.Keys)
{
Write-Host "`t ResourceGroup = $($ResourceGroup.ResourceGroupName) `t TagKey= $($key) `t Value = $($tags.Properties.TagsProperty.Item($($key)))"
}
foreach($res in $resourceNames)
{
Write-Host "ResourceName = $($res.Name)"
$tags=Get-AzTag -ResourceId $res.ResourceId
foreach($key in $tags.Properties.TagsProperty.Keys)
{
Write-Host "`t `t ResourceGroup = $($ResourceGroup.ResourceGroupName) `t ResourceName = $($res.Name) `t TagKey= $($key) `t Value = $($tags.Properties.TagsProperty.Item($($key)))"
}
}
}
# Sent the final output to CSV
$Output | Export-Csv -Path test.csv -NoClobber -NoTypeInformation -Append -Encoding UTF8 -Force
}
You are not adding the output you are printing with the Write-Host cmdlet to the $output array:
SubscriptionIds = Get-Content -Path "path for SubscriptionID.txt"
Foreach ($SubscriptionId in $SubscriptionIds) {
Try { $null = Set-AzContext -SubscriptionId $SubscriptionId }
catch [Exception] { write-host ("Error occured: " + $($_.Exception.Message)) -ForegroundColor Red; Exit }
Write-Host "Azure Login Session successful" -ForegroundColor Green -BackgroundColor Black
# Initialise output array
$Output = #()
# Collect all the groups from the current subscription
$ResourceGroups = Get-AzResourceGroup
foreach ($ResourceGroup in $ResourceGroups) {
Write-Host "Resource Group =$($ResourceGroup.ResourceGroupName)"
$resourceNames = Get-AzResource -ResourceGroupName $ResourceGroup.ResourceGroupName
$tags = Get-AzTag -ResourceId $ResourceGroup.ResourceId
foreach ($key in $tags.Properties.TagsProperty.Keys) {
$Output += "`t ResourceGroup = $($ResourceGroup.ResourceGroupName) `t TagKey= $($key) `t Value = $($tags.Properties.TagsProperty.Item($($key)))"
Write-Host "`t ResourceGroup = $($ResourceGroup.ResourceGroupName) `t TagKey= $($key) `t Value = $($tags.Properties.TagsProperty.Item($($key)))"
}
foreach ($res in $resourceNames) {
Write-Host "ResourceName = $($res.Name)"
$tags = Get-AzTag -ResourceId $res.ResourceId
foreach ($key in $tags.Properties.TagsProperty.Keys) {
$Output += "`t ResourceGroup = $($ResourceGroup.ResourceGroupName) `t TagKey= $($key) `t Value = $($tags.Properties.TagsProperty.Item($($key)))"
Write-Host "`t `t ResourceGroup = $($ResourceGroup.ResourceGroupName) `t ResourceName = $($res.Name) `t TagKey= $($key) `t Value = $($tags.Properties.TagsProperty.Item($($key)))"
}
}
}
# Sent the final output to CSV
$Output | Export-Csv -Path test.csv -NoClobber -NoTypeInformation -Append -Encoding UTF8 -Force
}
Try this one.
$Output = [System.Collections.ArrayList]::new()
$ResourceGroups = Get-AzResourceGroup
foreach ($ResourceGroup in $ResourceGroups) {
Write-Host "Resource Group =$($ResourceGroup.ResourceGroupName)"
$resourceNames = Get-AzResource -ResourceGroupName $ResourceGroup.ResourceGroupName
$tags = Get-AzTag -ResourceId $ResourceGroup.ResourceId
foreach ($key in $tags.Properties.TagsProperty.Keys) {
$csvObject = New-Object PSObject
Add-Member -inputObject $csvObject -memberType NoteProperty -name "ResourceGroup" -value $ResourceGroup.ResourceGroupName
Add-Member -inputObject $csvObject -memberType NoteProperty -name "ResourceName" -value ''
Add-Member -inputObject $csvObject -memberType NoteProperty -name "TagKey" -value $key
Add-Member -inputObject $csvObject -memberType NoteProperty -name "Value" -value $tags.Properties.TagsProperty.Item($($key))
$Output.Add($csvObject)
#$Output += "`t ResourceGroup = $($ResourceGroup.ResourceGroupName) `t TagKey= $($key) `t Value = $($tags.Properties.TagsProperty.Item($($key)))"
Write-Host "`t ResourceGroup = $($ResourceGroup.ResourceGroupName) `t TagKey= $($key) `t Value = $($tags.Properties.TagsProperty.Item($($key)))"
}
foreach ($res in $resourceNames) {
Write-Host "ResourceName = $($res.Name)"
$tags = Get-AzTag -ResourceId $res.ResourceId
foreach ($key in $tags.Properties.TagsProperty.Keys) {
$csvObject = New-Object PSObject
Add-Member -inputObject $csvObject -memberType NoteProperty -name "ResourceGroup" -value $ResourceGroup.ResourceGroupName
Add-Member -inputObject $csvObject -memberType NoteProperty -name "ResourceName" -value $res.Name
Add-Member -inputObject $csvObject -memberType NoteProperty -name "TagKey" -value $key
Add-Member -inputObject $csvObject -memberType NoteProperty -name "Value" -value $tags.Properties.TagsProperty.Item($($key))
$Output.Add($csvObject)
#$Output += "`t ResourceGroup = $($ResourceGroup.ResourceGroupName) `t TagKey= $($key) `t Value = $($tags.Properties.TagsProperty.Item($($key)))"
Write-Host "`t `t ResourceGroup = $($ResourceGroup.ResourceGroupName) `t ResourceName = $($res.Name) `t TagKey= $($key) `t Value = $($tags.Properties.TagsProperty.Item($($key)))"
}
}
}
$Output | Export-Csv -Path test.csv -NoClobber -NoTypeInformation -Append -Encoding UTF8 -Force
I have a script that creates a Public IPs report. I'm having problem with one VM having two NICs attached to it. My script is designed in a way, that VM name is unique key, upon which all the other data is correlated and assigned to main table. Is there any way to get around this? Here's my script:
#Data collection
$PIP = Get-AzPublicIpAddress
$pipOutput = $PIP | ForEach-Object {
[PSCustomObject]#{
"IP Name" = $_.Name
"IP Address" = $_.IpAddress
"Resource Group Name" = $_.ResourceGroupName
"Location" = $_.Location
"VM Name" = ""
"Network Interface" = ""
"Application" = $_.Tag.Application
"Environment" = $_.Tag.Environment
"Role" = $_.Tag.Role
"Decommission" = $_.Tag.Decommission
"Funding" = $_.Tag.Funding
"Provisioning State" = $_.ProvisioningState
"Allocation Method" = $_.PublicIpAllocationMethod
"Version" = $_.PublicIpAddressVersion
"Idle Timeout In Minutes" = $_.IdleTimeoutInMinutes
}
}
$VMs = Get-AzVm -status
$all = #{}
$end = #{}
foreach ($vm in $VMs) {
$VMNetworkInterfaceSplitToArray = $vm.NetworkProfile.NetworkInterfaces.id.Split('/')
$VMNetworkInterfaceObject = Get-AzNetworkInterface -ResourceGroupName $vm.ResourceGroupName -Name $VMNetworkInterfaceSplitToArray[$VMNetworkInterfaceSplitToArray.Count - 1]
try {
$VMPublicIpSplitToArray = ($VMNetworkInterfaceObject.IpConfigurations.publicipaddress.Id).Split('/')
$vm_Public_IP = (Get-AzPublicIpAddress -ResourceGroupName $vm.ResourceGroupName -Name $VMPublicIpSplitToArray[$VMPublicIpSplitToArray.Count - 1]).IpAddress
}
catch {
$vm_Public_IP = "n/a"
}
if($vm_Public_IP -ne "n/a")
{
$all.Add($vm_Public_IP,$vm.name)
$end.Add($vm_Public_IP,$VMNetworkInterfaceObject.name)
}
}
foreach ($ipadd in $pipOutput)
{
if($all.ContainsKey($ipadd."IP Address"))
{
$ipadd."VM Name"=$all[$ipadd."IP Address"]
}
else
{
$ipadd."VM Name"="n/a"
}
}
foreach ($ipadd in $pipOutput)
{
if($end.ContainsKey($ipadd."IP Address"))
{
$ipadd."Network Interface"=$end[$ipadd."IP Address"]
}
else
{
$ipadd."Network Interface"="n/a"
}
}
According to the error: Method invocation failed because [System.Management.Automation.PSObject] does not contain a method named 'op_Addition', I suggest you create an array to save all your PSCustomObject.
For example
Connect-AzAccount
$PIP = Get-AzPublicIpAddress
$pipOutput = $PIP | ForEach-Object {
[PSCustomObject]#{
"IP Name" = $_.Name
"IP Address" = $_.IpAddress
"Resource Group Name" = $_.ResourceGroupName
"Location" = $_.Location
"VM Name" = ""
"Network Interface" = ""
"Application" = $_.Tag.Application
"Environment" = $_.Tag.Environment
"Role" = $_.Tag.Role
"Decommission" = $_.Tag.Decommission
"Funding" = $_.Tag.Funding
"Provisioning State" = $_.ProvisioningState
"Allocation Method" = $_.PublicIpAllocationMethod
"Version" = $_.PublicIpAddressVersion
"Idle Timeout In Minutes" = $_.IdleTimeoutInMinutes
}
}
$vms =Get-AzVM
$all =#()
Foreach($vm in $vms){
$VMNetworkInterfaceToArray = $vm.NetworkProfile.NetworkInterfaces.id
foreach($r in $VMNetworkInterfaceToArray ){
$resource = Get-AzResource -ResourceId $r
$VMNetworkInterfaceObject=Get-AzNetworkInterface -Name $resource.Name -ResourceGroupName $resource.ResourceGroupName
try{
$VMPublicIp=Get-AzResource -ResourceId $VMNetworkInterfaceObject.IpConfigurations.publicipaddress.Id
$vm_Public_IP = (Get-AzPublicIpAddress -ResourceGroupName $VMPublicIp.ResourceGroupName -Name $VMPublicIp.Name).IpAddress
}catch {
$vm_Public_IP = "n/a"
}
if($vm_Public_IP -ne "n/a")
{
#create custom object to save the details your need
$obj= [PSCustomObject]#{"VmName"=$vm.Name
"VMPublicIP"=$vm_Public_IP
"VMNetworkInterface"=$VMNetworkInterfaceObject.Name
}
# save the object into array
$all +=$obj
}
}
}
Foreach($ipadd in $pipOutput){
foreach($a in $all){
if($a.VMPublicIP=$ipadd.'IP Address'){
$ipadd.'VM Name' =$a.VmName
$ipadd.'Network Interface'=$a.VMNetworkInterface
}else{
$ipadd.'VM Name' ="n/a"
$ipadd.'Network Interface'="n/a"
}
}
}
Update
Please change the script as below
Foreach($ipadd in $pipOutput){
foreach($a in $all){
if($ipadd.'IP Address'.Equals($a.VMPublicIP)){
$ipadd.'VM Name' =$a.VmName
$ipadd.'Network Interface'=$a.VMNetworkInterface
}else{
$ipadd.'VM Name' ="n/a"
$ipadd.'Network Interface'="n/a"
}
}
}
I have a PowerShell script which I've converted to a Workflow. The script is near identical, except for the few lines that need to be altered in order for it to be a Workflow.
However, for some reason it doesn't output like I think it should, and I am absolutely clueless as to why this would be the case.
Original PS script:
$DynatraceTenantID = "asdf"
$DynatraceToken = "asdf"
$DynatraceServer = "asdf"
$TagName = "env"
$TagValue = "dynatrace"
$result_array_altered = #()
$result_array_installed = #()
$result_array_notaltered = #()
$vms = Get-AzureRmResource -TagName $TagName -TagValue $TagValue | Where-Object {$_.ResourceType -like "Microsoft.Compute/virtualMachines"} | Where-Object {$_.Name -inotlike "MyVMx0"}
Foreach ($vm in $vms) {
$vm0 = Get-AzureRmVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Status
$vm1 = Get-AzureRmVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name
$vm2 = $vm1.Extensions
if ($vm2.Publisher -notcontains "dynatrace.ruxit"){
if ($vm0.Statuses.DisplayStatus -eq "VM running") {
Set-AzureRmVmExtension `
-Name "Dynatrace" `
-Publisher "dynatrace.ruxit" `
-ResourceGroupName "$($vm1.ResourceGroupName)" `
-Location "$($vm1.Location)" `
-VMName "$($vm1.Name)" `
-ExtensionType "oneAgentWindows" `
-TypeHandlerVersion "2.3" `
-Settings #{ "tenantId"=$DynatraceTenantID; "token"=$DynatraceToken;"server"=$DynatraceServer; }
$objAltered = New-Object -TypeName PSObject -Property #{
VMaltered = $($vm1.Name)
IDaltered = $($vm1.Id)
}
$result_array_altered += $objAltered
} else {
$objNotAltered = New-Object -TypeName PSObject -Property #{
VMnotAltered = $($vm1.Name)
IDnotAltered = $($vm1.Id)
}
$result_array_notaltered += $objNotAltered
}
} else {
$objInstalled = New-Object -TypeName PSObject -Property #{
VMinstalled = $($vm1.Name)
IDinstalled = $($vm1.Id)
}
$result_array_installed += $objInstalled
}
}
$result_array_altered | ConvertTo-Json
$result_array_installed | ConvertTo-Json
$result_array_notaltered | ConvertTo-Json
Outputs the following:
[
{
"IDinstalled": "/subscriptions/MY-SUBSCRIPTION/resourceGroups/virtual-machines/providers/Microsoft.Compute/virtualMachines/MyVMw0",
"VMinstalled": "MyVMw0"
},
{
"IDinstalled": "/subscriptions/MY-SUBSCRIPTION/resourceGroups/virtual-machines/providers/Microsoft.Compute/virtualMachines/MyVMw1",
"VMinstalled": "MyVMw1"
}
]
The converted PowerShell to PS Workflow:
workflow InstallDynatrace {
$DynatraceTenantID = "asdf"
$DynatraceToken = "asdf"
$DynatraceServer = "asdf"
$TagName = "env"
$TagValue = "dynatrace"
$result_array_altered = #()
$result_array_installed = #()
$result_array_notaltered = #()
$vms = Get-AzureRmResource -TagName $TagName -TagValue $TagValue | Where-Object {$_.ResourceType -like "Microsoft.Compute/virtualMachines"} | Where-Object {$_.Name -inotlike "MyVMx0"}
Foreach -parallel ($vm in $vms) {
$vm0 = Get-AzureRmVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Status
$vm1 = Get-AzureRmVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name
$vm2 = $vm1.Extensions
if ($vm2.Publisher -notcontains "dynatrace.ruxit"){
if ($vm0.Statuses.DisplayStatus -eq "VM running") {
Set-AzureRmVmExtension `
-Name "Dynatrace" `
-Publisher "dynatrace.ruxit" `
-ResourceGroupName "$($vm1.ResourceGroupName)" `
-Location "$($vm1.Location)" `
-VMName "$($vm1.Name)" `
-ExtensionType "oneAgentWindows" `
-TypeHandlerVersion "2.3" `
-Settings #{ "tenantId"=$DynatraceTenantID; "token"=$DynatraceToken;"server"=$DynatraceServer; }
$objAltered = New-Object -TypeName PSObject -Property #{
VMaltered = $($vm1.Name)
IDaltered = $($vm1.Id)
}
} else {
$objNotAltered = New-Object -TypeName PSObject -Property #{
VMnotAltered = $($vm1.Name)
IDnotAltered = $($vm1.Id)
}
}
} else {
$objInstalled = New-Object -TypeName PSObject -Property #{
VMinstalled = $($vm1.Name)
IDinstalled = $($vm1.Id)
}
}
$workflow:result_array_altered += $objAltered
$workflow:result_array_notaltered += $objNotAltered
$workflow:result_array_installed += $objInstalled
}
$result_array_altered | ConvertTo-Json
$result_array_installed | ConvertTo-Json
$result_array_notaltered | ConvertTo-Json
}
Outputs the following:
PS C:\WINDOWS\system32> InstallDynatrace
[
{
"VMnotAltered": "MyVMw1",
"IDnotAltered": "/subscriptions/MY-SUBSCRIPTION/resourceGroups/virtual-machines/providers/Microsoft.Compute/virtualMachines/MyVMw1",
"PSComputerName": "localhost",
"PSShowComputerName": true,
"PSSourceJobInstanceId": "36c288df-41c3-4b61-9a6c-445707f76bea"
},
{
"VMnotAltered": "MyVMw0",
"IDnotAltered": "/subscriptions/MY-SUBSCRIPTION/resourceGroups/virtual-machines/providers/Microsoft.Compute/virtualMachines/MyVMw0",
"PSComputerName": "localhost",
"PSShowComputerName": true,
"PSSourceJobInstanceId": "36c288df-41c3-4b61-9a6c-445707f76bea"
}
]
Note how the original script shows that results array to be VMinstalled and IDinstalled, whereas the workflow shows as VMnotAltered and IDnotAltered, meaning that it saw the VMs as NOT having Dynatrace installed (line 19), didn't see it Running (line 20) and just added it to the Not Altered array.
Any ideas where I'm going wrong?
UPDATED FOR THEO ANSWER
PS C:\WINDOWS\system32>
workflow InstallDynatrace {
$DynatraceTenantID = "asdf"
$DynatraceToken = "asdf"
$DynatraceServer = "asdf"
$TagName = "env"
$TagValue = "dynatrace"
$result_array_altered = #()
$result_array_installed = #()
$result_array_notaltered = #()
$vms = Get-AzureRmResource -TagName $TagName -TagValue $TagValue | Where-Object {$_.ResourceType -like "Microsoft.Compute/virtualMachines"} | Where-Object {$_.Name -inotlike "MyVMx0"}
Foreach -parallel ($vm in $vms) {
$vm0 = Get-AzureRmVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Status
$vm1 = Get-AzureRmVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name
$vm2 = $vm1.Extensions
if ($vm2.Publisher -ne "dynatrace.ruxit"){
if ($vm0.Statuses.DisplayStatus -eq "VM running") {
Set-AzureRmVmExtension `
-Name "Dynatrace" `
-Publisher "dynatrace.ruxit" `
-ResourceGroupName "$($vm1.ResourceGroupName)" `
-Location "$($vm1.Location)" `
-VMName "$($vm1.Name)" `
-ExtensionType "oneAgentWindows" `
-TypeHandlerVersion "2.3" `
-Settings #{ "tenantId"=$DynatraceTenantID; "token"=$DynatraceToken;"server"=$DynatraceServer; }
$objAltered = New-Object -TypeName PSObject -Property #{
VMaltered = $($vm1.Name)
IDaltered = $($vm1.Id)
}
$workflow:result_array_altered += $objAltered
} else {
$objNotAltered = New-Object -TypeName PSObject -Property #{
VMnotAltered = $($vm1.Name)
IDnotAltered = $($vm1.Id)
}
$workflow:result_array_notaltered += $objNotAltered
}
} else {
$objInstalled = New-Object -TypeName PSObject -Property #{
VMinstalled = $($vm1.Name)
IDinstalled = $($vm1.Id)
}
$workflow:result_array_installed += $objInstalled
}
}
$workflow:result_array_altered | ConvertTo-Json
$workflow:result_array_installed | ConvertTo-Json
$workflow:result_array_notaltered | ConvertTo-Json
}
InstallDynatrace
[
{
"VMnotAltered": "MyVMw0",
"IDnotAltered": "/subscriptions/asdf/resourceGroups/virtual-machines/providers/Microsoft.Compute/virtualMachines/MyVMw0",
"PSComputerName": "localhost",
"PSShowComputerName": true,
"PSSourceJobInstanceId": "d23d8e5b-dc3c-475f-82fe-968a3eeef946"
},
{
"VMnotAltered": "MyVMw1",
"IDnotAltered": "/subscriptions/asdf/resourceGroups/virtual-machines/providers/Microsoft.Compute/virtualMachines/MyVMw1",
"PSComputerName": "localhost",
"PSShowComputerName": true,
"PSSourceJobInstanceId": "d23d8e5b-dc3c-475f-82fe-968a3eeef946"
}
]
PS C:\WINDOWS\system32>
You have made the same error you did earlier I'm afraid.
Where in the script you add the object to the corresponding array where it should be added, namely right after creating it inside the if or else block, in the Workflow you add them all at the end of the loop..
This means that regardless of the outcome of the if {...} else {...} tests, you add them anyway.
This should do things in the right place:
Foreach -parallel ($vm in $vms) {
$vm0 = Get-AzureRmVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Status
$vm1 = Get-AzureRmVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name
$vm2 = $vm1.Extensions
if ($vm2.Publisher -notcontains "dynatrace.ruxit"){ # should be -ne I think
if ($vm0.Statuses.DisplayStatus -eq "VM running") {
Set-AzureRmVmExtension `
-Name "Dynatrace" `
-Publisher "dynatrace.ruxit" `
-ResourceGroupName "$($vm1.ResourceGroupName)" `
-Location "$($vm1.Location)" `
-VMName "$($vm1.Name)" `
-ExtensionType "oneAgentWindows" `
-TypeHandlerVersion "2.3" `
-Settings #{ "tenantId"=$DynatraceTenantID; "token"=$DynatraceToken;"server"=$DynatraceServer; }
$objAltered = New-Object -TypeName PSObject -Property #{
VMaltered = $($vm1.Name)
IDaltered = $($vm1.Id)
}
# this is where you add the object to the $workflow:result_array_altered array
$workflow:result_array_altered += $objAltered
}
else {
$objNotAltered = New-Object -TypeName PSObject -Property #{
VMnotAltered = $($vm1.Name)
IDnotAltered = $($vm1.Id)
}
# this is where you add the object to the $workflow:result_array_notaltered array
$workflow:result_array_notaltered += $objNotAltered
}
}
else {
$objInstalled = New-Object -TypeName PSObject -Property #{
VMinstalled = $($vm1.Name)
IDinstalled = $($vm1.Id)
}
# this is where you add the object to the $workflow:result_array_installed array
$workflow:result_array_installed += $objInstalled
}
}
$workflow:result_array_altered | ConvertTo-Json
$workflow:result_array_notaltered | ConvertTo-Json
$workflow:result_array_installed | ConvertTo-Json
Then, at the end of the workflow, you outputted the arrays you still had in memory from the earlier script version ($result_array_altered | ConvertTo-Json etc. I have changed that to match the new arrays for you.
Also, isn't $vm2.Publisher just a single string? In that case, change the lines
if ($vm2.Publisher -notcontains "dynatrace.ruxit")
into
if ($vm2.Publisher -ne "dynatrace.ruxit")
(-notcontains checks a value in an array where -ne tests for the 'not-equalness' of a single object, so a string in this case)
UPDATE
I MAY have found an answer for the unwanted extra information here
It may look ugly, but try this at the end of the workflow:
$workflow:result_array_altered | Select-Object -Property * -ExcludeProperty PSComputerName, PSShowComputerName, PSSourceJobInstanceId | ConvertTo-Json
$workflow:result_array_installed | Select-Object -Property * -ExcludeProperty PSComputerName, PSShowComputerName, PSSourceJobInstanceId | ConvertTo-Json
$workflow:result_array_notaltered | Select-Object -Property * -ExcludeProperty PSComputerName, PSShowComputerName, PSSourceJobInstanceId | ConvertTo-Json