My Powershell script is not explicitly calling for any specific resources but I am getting "ErrorCode: TargetResourceNotFound" error - azure

My Powershell script is not explicitly calling for any specific resources but I am getting "ErrorCode: TargetResourceNotFound" error. I have attached the error in the image. What am I missing?
$subs = Get-AzSubscription | Where-Object {$_.Name -like "*-NonProd"}
foreach ($sub in $subs)
{
Select-AzSubscription -SubscriptionId $sub.Id
$RGs = Get-AzResourceGroup | Where-Object {$_.ResourceGroupName -like "*Infra"}
foreach ($RG in $RGs)
{
$NetworkWatchers = Get-AzNetworkWatcher
$NSGs = (Get-AzNetworkSecurityGroup).Id
foreach ($NSG in $NSGs)
{
foreach ($NetworkWatcher in $NetworkWatchers)
{
$Status = Get-AzNetworkWatcherFlowLogStatus -NetworkWatcherName $NetworkWatcher.Name
ResourceGroupName $RG.ResourceGroupName -TargetResourceId $NSG -Verbose
}
if (($Status).Enabled -eq $true)
{
Write-Output "$NSG in $(($sub).Name) has FlowLogs Enabled" | Tee-Object -FilePath 'C:\Users\user1\downloads\Output.txt' -Verbose -Append
}
if (($Status).Enabled -ne $true)
{
Write-Output "$NSG in $(($sub).Name) does not have FlowLogs Enabled" | Tee-Object -FilePath 'C:\Users\user1\downloads\Output.txt' -Verbose -Append
}
}
}
}
enter code here
Error Attached

Network Watchers are usually in a hidden resource group, and perhaps you are trying to find one in one of the available RGs. Try omitting the RG factor and use
$subs = Get-AzSubscription | Where-Object { $_.Name -like "*-NonProd" }
foreach ($sub in $subs) {
Select-AzSubscription -SubscriptionId $sub.Id
$NetworkWatchers = Get-AzNetworkWatcher
$NSGs = (Get-AzNetworkSecurityGroup).Id
foreach ($NSG in $NSGs) {
foreach ($NetworkWatcher in $NetworkWatchers) {
$Status = Get-AzNetworkWatcherFlowLogStatus -NetworkWatcher $NetworkWatcher -TargetResourceId $NSG -Verbose
}
if (($Status).Enabled -eq $true) {
Write-Output "$NSG in $(($sub).Name) has FlowLogs Enabled" | Tee-Object -FilePath 'C:\Users\user1\downloads\Output.txt' -Verbose -Append
}
if (($Status).Enabled -ne $true) {
Write-Output "$NSG in $(($sub).Name) does not have FlowLogs Enabled" | Tee-Object -FilePath 'C:\Users\user1\downloads\Output.txt' -Verbose -Append
}
}
}
I am able to get all flow logs configuration status.

Here is another approach:
I tried to reproduce the same in my environment and got the same error as below:
The error TargetResourceNotFound usually occurs if you are passing invalid resource group name or subscription name.
To confirm whether the resource group or subscription exists, execute the below code lines separately like below:
$subs = Get-AzSubscription | Where-Object {$_.Name -like "*-name"}
$subs
$RGs = Get-AzResourceGroup | Where-Object {$_.ResourceGroupName -like "*name"}
$RGs
The error states that Target resource identifier /subscriptions/subid/resourceGroups/RG/providers/Microsoft.Network/networkWatchers/*** not found in the region westeurope. Cross-verify whether the Network Watcher exists.
I am able to get the status of the Network Watcher successfully when I passed valid subscription and Resource group like below:
If the error still persists, try excluding the $RGs = Get-AzResourceGroup | Where-Object {$_.ResourceGroupName -like "*name"} and execute.

I appreciate your assistance.
I got it working by changing -NetworkWatcherName $NetworkWatcher.Name to -NetworkWatcherName $NetworkWatcher.ResourceGroupName
foreach ($NSG in $NSGs)
{
# $NSG.Id
# $NSGid = $NSG.Id
foreach ($NetworkWatcher in $NetworkWatchers)
{
$Status = Get-AzNetworkWatcherFlowLogStatus -NetworkWatcherName $NetworkWatcher.ResourceGroupName -ResourceGroupName $RG.ResourceGroupName -TargetResourceId $NSG -Verbose -ErrorAction SilentlyContinue
if (($Status).Enabled -eq $true)
{
Write-Output "$NSG in $(($sub).Name) has FlowLogs Enabled" | Tee-Object -FilePath 'C:\Users\A240379\downloads\OutEnabled.csv' -Verbose -Append
}
if (($Status).Enabled -ne $true)
{
Write-Output "$NSG in $(($sub).Name) does not have FlowLogs Enabled" | Tee-Object -FilePath 'C:\Users\A240379\downloads\OutNotEnabled.csv' -Verbose -Append
}
}
}

Related

Get running VMs on Azure

I have the below code to check daily if all the VMs that are meant to auto-start have started successfully.
$Date = (Get-Date -Format "dd-MM-yyyy HH-mm").toString()
$Results = "C:\temp\DailyChecks_$($Date).txt"
$Cred = get-credential -UserName 'AZ-User'
Connect-AzAccount -Tenant 'TenantID' -credential $Cred | out-null
$fCount = (Get-AzVM -Status | Where-Object { $_.tags['Managed By'] -like 'Manager' }).count
do {
$rCount = (Get-AzVM -Status | Where-Object { $_.tags['Managed By'] -like 'Manager' -and $_.PowerState -eq 'VM Running' }).count
if($rCount -lt $fCount)
{
write-host "There are $rCount VMs running, checking again"
}
elseif($rCount -eq $fCount){write-host "There are $rCount VMs running, exiting loop"}
}until($fCount -eq $rCount)
Get-AzVM -Status | Where-Object { $_.tags['Managed By'] -like 'Manager' } |
Select-Object Name, PowerState | Format-Table | out-file $Results
I have a couple of questions:
Is there a better way to write this code?
How can I check if the code has been running for longer than 30 minutes and yet not all VMs are running?
You can determine for how much the time the script is running by using a StopWatch object.
$sw = [System.Diagnostics.Stopwatch]::new()
$sw.Start()
Whenever you want, just check the elapsed time by checking the elapsed property
$sw.Elapsed
$sw.Elapsed.TotalSeconds
Write-Host "Time elapsed: $([Math]::Round($sw.Elapsed.TotalMinutes,0)) min $($sw.Elapsed.Seconds) seconds"

How to get specifi list of Virtual Machine Status from Azure using powershell from Excel sheet

I am pretty much new to PowerShell and we have customer requirement that they will share Azure VM details in Excel sheet with below columns.
we have to get VM Status details from all the subscriptions & ResourceGroup using the Powershell script.
Outuput:
I am able to perform for single RSG and VM values by using the below code
$SubscriptionName = Get-AzSubscription -SubscriptionId $subscriptionId
$RG = "rgp-use2-prd-bioportalbiopeople1"
$RSGName = Get-AzResourceGroup -Name $RG
$VMs = Get-AzVM -Name "vmbppapiv1prd02"
$VMState = (Get-AzVM -Name $VM -ResourceGroupName $RG -Status).Statuses
$vmOutput = $VMs | ForEach-Object {
[PSCustomObject]#{
"Resource Group Name" = $RSGName.ResourceGroupName
"Subscription Name" = $SubscriptionName.Name
"VM Name" = $_.Name
"VM Type" = $_.StorageProfile.osDisk.osType
"VM Statss" = ($VMState | where code -Like 'PowerState/*')[0].DisplayStatus
}
}
$vmOutput | Format-Table -AutoSize
$vmOutput | export-csv C:\Projects\data.csv
I can't test this myself, but you will have to create nested loops to get the details for all subscriptions and resourcegroups.
Something like this:
$subscriptions = Get-AzSubscription -TenantId "aaaa-aaaa-aaaa-aaaa" # enter the tenant ID here
$VMs = Get-AzVM -Name "vmbppapiv1prd02"
$vmOutput = foreach ($vm in $VMs) {
foreach ($subscription in $subscriptions) {
Set-AzContext -SubscriptionId $subscription.Id
(Get-AzResourceGroup).ResourceGroupName | ForEach-Object {
$vmState = (Get-AzVM -Name $vm.Name -ResourceGroupName $_ -Status).Statuses
[PSCustomObject]#{
"Resource Group Name" = $_
"Subscription Name" = $Subscription.Name
"VM Name" = $vm.Name
"VM Type" = $vm.StorageProfile.osDisk.osType
"VM Status" = ($vmState | where code -Like 'PowerState/*')[0].DisplayStatus
}
}
}
}
$vmOutput | Format-Table -AutoSize
$vmOutput | Export-Csv -Path 'C:\Projects\data.csv' -NoTypeInformation

Azure VM OS Build - Powershell

I am trying to create a powershell command to loop through all my Azure subscriptions and get the OS build number of the VMs
param(
# Specify the location of the audit file
$csvFilePath = "C:\agentAudit.csv"
)
cls
$ErrorActionPreference = 'Stop'
Write-Host "Validating Azure Accounts..."
try{
$subscriptionList = Get-AzureRmSubscription | Sort SubscriptionName
}
catch {
Write-Host "Reauthenticating..."
Login-AzureRmAccount | Out-Null
$subscriptionList = Get-AzureRmSubscription | Sort SubscriptionName
}
if (Test-Path $csvFilePath) {
Remove-Item -Path $csvFilePath
}
foreach($subscription in $subscriptionList) {
Select-AzureRmSubscription -SubscriptionId $subscription.SubscriptionId | Out-Null
Write-Output "`n Working on subscription: $($subscription.SubscriptionName) `n"
$vms = Get-AzureRmVM -WarningAction Ignore
foreach ($vm in $vms) {
$VMs = Get-AzureRmVM
$vmlist = #()
$VMs | ForEach-Object {
$VMObj = New-Object -TypeName PSObject
$VMObj | Add-Member -MemberType Noteproperty -Name "VM Name" -Value $_.Name
$VMObj | Add-Member -MemberType Noteproperty -Name "OS type" -Value $_.StorageProfile.ImageReference.Sku
$VMObj | Add-Member -MemberType Noteproperty -Name "OS Offer" -Value $_.StorageProfile.ImageReference.Offer
$VMObj | Add-Member -MemberType Noteproperty -Name "OS Publisher" -Value $_.StorageProfile.ImageReference.Publisher
$VMObj | Add-Member -MemberType Noteproperty -Name "OS Version" -Value $_.StorageProfile.ImageReference.Version
$vmlist += $VMObj
}
$vmlist
}
}
I am pretty new to to Powershell and still learning to understand and write PS
Long time back i created a script for generating the Azure inventory. May be this can help you. You just need to tweak it a bit
Add-AzureRmAccount
$SubscriptionNames = "Prototypes","Development"
foreach($SubscriptionName in $SubscriptionNames)
{
try
{
Select-AzureRmSubscription -SubscriptionName $SubscriptionName
$VMinventory = Get-AzurermVM -ErrorAction Stop
$OutputPath = "C:\VMInventoryRM-" + $SubscriptionName + ".csv"
$report=#()
foreach ($vm in $VMinventory)
{
$VMinfo = " " | select Powerstate, Location, VMSize
# Display
write-host($vm.Name)
$vmStatus = $null
$Location = $null
$VMSize = $null
$vmStatus = (get-azurermvm -Name $vm.Name -ResourceGroupName $vm.ResourceGroupName -Status).Statuses[1].Code
$Location = $vm.Location
$VMSize = $vm.HardwareProfile.VmSize
$VMinfo.Powerstate = $vmStatus
$VMinfo.Location = $Location
$VMinfo.VMSize = $VMSize
$Report += $VMinfo
$i++
}
$Report | export-csv $OutputPath -NoTypeInformation
}
catch
{}
}
I found the answer in the below technet article
function Get-WindowsVersion {
<#
.SYNOPSIS
List Windows Version from computer. Compatible with PSVersion 3 or higher.
.DESCRIPTION
List Windows Version from computer. Compatible with PSVersion 3 or higher.
.PARAMETER ComputerName
Name of server to list Windows Version from remote computer.
.PARAMETER SearchBase
AD-SearchBase of server to list Windows Version from remote computer.
.PARAMETER History
List History Windows Version from computer.
.PARAMETER Force
Disable the built-in Format-Table and Sort-Object.
.NOTES
Name: Get-WindowsVersion.psm1
Author: Johannes Sebald
Version: 1.2.5
DateCreated: 2016-09-13
DateEdit: 2018-07-11
.LINK
https://www.dertechblog.de
.EXAMPLE
Get-WindowsVersion
List Windows Version on local computer with built-in Format-Table and Sort-Object.
.EXAMPLE
Get-WindowsVersion -ComputerName pc1
List Windows Version on remote computer with built-in Format-Table and Sort-Object.
.EXAMPLE
Get-WindowsVersion -ComputerName pc1,pc2
List Windows Version on multiple remote computer with built-in Format-Table and Sort-Object.
.EXAMPLE
Get-WindowsVersion -SearchBase "OU=Computers,DC=comodo,DC=com" with built-in Format-Table and Sort-Object.
List Windows Version on Active Directory SearchBase computer.
.EXAMPLE
Get-WindowsVersion -ComputerName pc1,pc2 -Force
List Windows Version on multiple remote computer and disable the built-in Format-Table and Sort-Object.
.EXAMPLE
Get-WindowsVersion -History with built-in Format-Table and Sort-Object.
List History Windows Version on local computer.
.EXAMPLE
Get-WindowsVersion -ComputerName pc1,pc2 -History
List History Windows Version on multiple remote computer with built-in Format-Table and Sort-Object.
.EXAMPLE
Get-WindowsVersion -ComputerName pc1,pc2 -History -Force
List History Windows Version on multiple remote computer and disable built-in Format-Table and Sort-Object.
#>
[cmdletbinding()]
param (
[parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[string[]]$ComputerName = "localhost",
[string]$SearchBase,
[switch]$History,
[switch]$Force
)
if ($($PsVersionTable.PSVersion.Major) -gt "2") {
# SearchBase
if ($SearchBase) {
if (Get-Command Get-AD* -ErrorAction SilentlyContinue) {
if (Get-ADOrganizationalUnit -Filter "distinguishedName -eq '$SearchBase'" -ErrorAction SilentlyContinue) {
$Table = Get-ADComputer -SearchBase $SearchBase -Filter *
$ComputerName = $Table.Name
}
else {Write-Warning "No SearchBase found"}
}
else {Write-Warning "No AD Cmdlet found"}
}
# Loop 1
$Tmp = New-TemporaryFile
foreach ($Computer in $ComputerName) {
if (Test-Connection -ComputerName $Computer -Count 1 -ErrorAction SilentlyContinue) {
try {
$WmiObj = Get-WmiObject Win32_OperatingSystem -ComputerName $Computer
}
catch {
Write-Warning "$Computer no wmi access"
}
if ($WmiObj) {
# Variables
$WmiClass = [WmiClass]"\\$Computer\root\default:stdRegProv"
$HKLM = 2147483650
$Reg1 = "SOFTWARE\Microsoft\Windows NT\CurrentVersion"
$Reg2 = "SYSTEM\Setup"
if ($History) {$KeyArr = ($WmiClass.EnumKey($HKLM, $Reg2)).snames -like "Source*"} else {$KeyArr = $Reg1}
# Loop 2
foreach ($Key in $KeyArr) {
if ($History) {$Reg = "$Reg2\$Key"} else {$Reg = $Key}
$Major = $WmiClass.GetDWordValue($HKLM, $Reg, "CurrentMajorVersionNumber").UValue
$Minor = $WmiClass.GetDWordValue($HKLM, $Reg, "CurrentMinorVersionNumber").UValue
$Build = $WmiClass.GetStringValue($HKLM, $Reg, "CurrentBuildNumber").sValue
$UBR = $WmiClass.GetDWordValue($HKLM, $Reg, "UBR").UValue
$ReleaseId = $WmiClass.GetStringValue($HKLM, $Reg, "ReleaseId").sValue
$ProductName = $WmiClass.GetStringValue($HKLM, $Reg, "ProductName").sValue
$ProductId = $WmiClass.GetStringValue($HKLM, $Reg, "ProductId").sValue
$InstallTime1 = $WmiClass.GetQWordValue($HKLM, $Reg, "InstallTime").UValue
$InstallTime2 = ([datetime]::FromFileTime($InstallTime1))
# Variables Windows 6.x
if ($Major.Length -le 0) {$Major = $WmiClass.GetStringValue($HKLM, $Reg, "CurrentVersion").sValue}
if ($ReleaseId.Length -le 0) {$ReleaseId = $WmiClass.GetStringValue($HKLM, $Reg, "CSDVersion").sValue}
if ($InstallTime1.Length -le 0) {$InstallTime2 = ([WMI]"").ConvertToDateTime($WmiObj.InstallDate)}
# Add Points
if (-not($Major.Length -le 0)) {$Major = "$Major."}
if (-not($Minor.Length -le 0)) {$Minor = "$Minor."}
if (-not($UBR.Length -le 0)) {$UBR = ".$UBR"}
# Output
$Output = New-Object -TypeName PSobject
$Output | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer.toUpper()
$Output | Add-Member -MemberType NoteProperty -Name ProductName -Value $ProductName
$Output | Add-Member -MemberType NoteProperty -Name WindowsVersion -Value $ReleaseId
$Output | Add-Member -MemberType NoteProperty -Name WindowsBuild -Value "$Major$Minor$Build$UBR"
$Output | Add-Member -MemberType NoteProperty -Name ProductId -Value $ProductId
$Output | Add-Member -MemberType NoteProperty -Name InstallTime -Value $InstallTime2
$Output | Export-Csv -Path $Tmp -Append
}
}
}
else {Write-Warning "$Computer not reachable"}
}
# Output
if ($Force) {Import-Csv -Path $Tmp} else {Import-Csv -Path $Tmp | Sort-Object -Property ComputerName, WindowsVersion | Format-Table -AutoSize}
}
else {Write-Warning "PSVersion to low"}
}
https://gallery.technet.microsoft.com/scriptcenter/Get-WindowsVersion-can-0726c5d4#
Thank You Johannes Sebald

How to use PowerShell parameter in Jenkins

I am using PowerShell to automate VM start/stop in Azure. However, when I set the $OPTION parameter it doesn't do anything. I have if/elseif/else statements.
See code below:
Add-AzureRmAccount -Credential $psCred -TenantId <removed> -ServicePrincipal
Get-AzureRmSubscription -SubscriptionName "<removed>"
#Get VMs using Tags
$vms = (Find-AzureRmResource | Where-Object {($_.tags.Project -eq "DevOps") -And ($_.tags.Test -eq "ernest")} | Select Name, ResourceGroupName)
$vms
Write-Output "Number of Virtual Machines: $($vms.Name.Count)"
foreach($VM in $vms)
{
if ($OPTION -eq "start" -And $VM.ResourceType -eq "Microsoft.Compute/virtualMachines")
{
Write-Output "Starting :- $VM.Name in $VM.ResourceGroupName"
Start-AzureRmVM -ResourceGroupName $VM.ResourceGroupName -Name $VM.Name -Verbose
Write-Output $VM.Name "has started successfully"
Write-Output "Writing output to workspace"
Get-AzureRmVM -Status | Where-Object {($_.tags.Project -eq "DevOps") -And ($_.tags.Test -eq "ernest")} | Select Name, ResourceGroupName, PowerState > VM_Start_Info-$(get-date -f yyyy-MM-dd).tsv
}
elseif ($OPTION -eq "stop" -And $VM.ResourceType -eq "Microsoft.Compute/virtualMachines")
{
Write-Output "Deallocating :- $VM.Name in $VM.ResourceGroupName"
Stop-AzureRmVM -ResourceGroupName $VM.ResourceGroupName -Name $VM.Name -Force -Verbose
Write-Output $VM.Name "has been deallocated successfully"
Write-Output "Writing output to workspace"
Get-AzureRmVM -Status | Where-Object {($_.tags.Project -eq "DevOps") -And ($_.tags.Test -eq "ernest")} | Select Name, ResourceGroupName, PowerState > VM_Stopped_Info-$(get-date -f yyyy-MM-dd).tsv
}
else
{
Write-Output "No option selected, select an option"
}
}
Write-Output "Script complete"
I had to add the $env:OPTION parameter to the Execute Powershell window. It works now

Wait until all threads complete before running next task

I would wrap everything inside foreach($computer in $computers) in a Start-Job to make them run simultaneously. The only problem is, I need to wait for all the jobs to complete before I do the ConvertTo-Json at the bottom.
$sb = "OU=some,OU=ou,DC=some,DC=domain"
$computers = Get-ADComputer -Filter {(Enabled -eq $true)} -SearchBase "$sb" -Properties *
$hasmanufacturer = New-Object System.Collections.Generic.List[System.Object]
foreach($computer in $computers)
{
$drives = try{#(Get-WMIObject -Class Win32_CDROMDrive -Property * -ComputerName $computer.Name -ErrorAction Stop)} catch {$null}
foreach($drive in $drives)
{
if($drive.Manufacturer)
{
$hasmanufacturer.Add($computer)
continue
}
} # inner foreach
}
ConvertTo-Json $hasmanufacturer
Use a Get-Job | Wait-Job before executing the ConvertTo-Json
How about using the array of computer names as a parameter to Invoke-Command. It will run, by default, 32 concurrent remote sessions. The number can be changed with the -Throttle parameter.
$computers = Get-ADComputer -Filter {(Enabled -eq $true)} -SearchBase "OU=Servers,DC=xxx,DC=com" -Properties Name |
Where-Object { $_.Name -match 'LAX_*' } |
ForEach-Object { $_.Name }
$computers
$j = Invoke-Command `
-ComputerName $computers `
-ScriptBlock { Get-WMIObject -Class Win32_CDROMDrive -Property * -ErrorAction Stop } `
-AsJob
while ( (Get-Job -Id $j.Id).Status -eq 'Running') {}
Get-Job -Id $j.Id | Wait-Job
$results = Receive-Job -Id $j.Id
$results

Resources