Azure VM OS Build - Powershell - azure

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

Related

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

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
}
}
}

Export Azure Subscriptions and owners (need PowerShell script)

I need help to create a script.
The task is to in Azure to export Subscriptions and owners of these subscriptions to CSV file. I assume I will be using powershell for this task
Please help!
You can use the below PowerShell script to pull the list of users which has the owner access to the subscription.
Connect-AzAccount
$sublist= Get-AzSubscription
foreach ($item in $sublist){
$scopeappend= "/subscriptions/"+$item.Id
$export=(Get-AzRoleAssignment -RoleDefinitionId "8e3af657-a8ff-443c-a75c-2fe8c4bcb635" -Scope $tdt | where {($_.ObjectType -EQ "user") -and ($_.Scope -EQ $scopeappend) } ) | select DisplayName,SignInName
}
$export|Export-Csv -Path C:\test.csv
I have tested the above PowerShell script and it is working fine for me.
You can refer to this documentation for For-each loop syntax as well.
I figure out the solution. Please see below.
$subs = Get-AzSubscription
$filename = "Subs_CoAdmins"+(Get-Date -UFormat "%Y-%m-%d_%H-%m-%S")+".xlsx"
$allRBACs = #()
foreach ($sub in $subs) {
if (Select-AzSubscription -SubscriptionName $sub.Name) {
if ($rbacs = Get-AzRoleAssignment -IncludeClassicAdministrators) {
foreach ($rbac in $rbacs) {
if (($rbac.Scope -like "/subscriptions/*") -and ($rbac.ObjectType -eq "Microsoft.Authorization/classicAdministrators") -and ($sub.SubscriptionPolicies.QuotaId -like "*MSDN*")) {
$rbacObj = New-Object -TypeName psobject
$rbacObj | Add-Member -MemberType NoteProperty -Name Subscription -Value $sub.Name
$rbacObj | Add-Member -MemberType NoteProperty -Name SubscriptionId -Value $sub.Id
$rbacObj | Add-Member -MemberType NoteProperty -Name Scope -Value $rbac.Scope
$rbacObj | Add-Member -MemberType NoteProperty -Name RoleDefinitionName -Value $rbac.RoleDefinitionName
$rbacObj | Add-Member -MemberType NoteProperty -Name RoleDefinitionId -Value $rbac.RoleDefinitionId
$rbacObj | Add-Member -MemberType NoteProperty -Name DisplayName -Value $rbac.DisplayName
$rbacObj | Add-Member -MemberType NoteProperty -Name SignInName -Value $rbac.SignInName
$rbacObj | Add-Member -MemberType NoteProperty -Name ObjectType -Value $rbac.ObjectType
$rbacObj | Add-Member -MemberType NoteProperty -Name SubQuotaId -Value $sub.SubscriptionPolicies.QuotaId
$allRBACs += $rbacObj
}
}
}
}
}
$allRBACs | Export-Excel ./$filename -AutoSize -AutoFilter

Export Multiple Azure AD group members

I am using below code snippet, Instead of -ALL I am trying to pass specific ObjectId or filter group name but getting below error. pls help to fix this.
$groups=Get-AzureADGroup -ObjectId "Group1" - Works fine with one but not with multiple ObjectId
$groups=Get-AzureADGroup -filter{Name -like "ABC*"} - Get-AzureADGroup : Cannot evaluate parameter 'Filter'
Connect-AzureAD
$groups=Get-AzureADGroup -All $true
$resultsarray =#()
ForEach ($group in $groups){
$members = Get-AzureADGroupMember -ObjectId $group.ObjectId -All $true
ForEach ($member in $members){
$UserObject = new-object PSObject
$UserObject | add-member -membertype NoteProperty -name "Group Name" -Value $group.DisplayName
$UserObject | add-member -membertype NoteProperty -name "Member Name" -Value $member.DisplayName
$UserObject | add-member -membertype NoteProperty -name "ObjType" -Value $member.ObjectType
$UserObject | add-member -membertype NoteProperty -name "UserType" -Value $member.UserType
$UserObject | add-member -membertype NoteProperty -name "UserPrinicpalName" -Value $member.UserPrincipalName
$resultsarray += $UserObject
}
}
$resultsarray | Export-Csv -Encoding UTF8 -Delimiter ";" -Path "C:\scripts\output.csv" -NoTypeInformation
$groups=Get-AzureADGroup -All
$result=new-object system.colletions.arraylist
foreach($group in $groups)
{
$members=$group.members
foreach($member in $members)
{
$result.add(
[PSCustomObject]#{
"Group Name"=$group.DisplayName
"Member Name"=$member.DisplayName
"ObjType"=$member.ObjectType
"UserType"=$member.UserType
"UserPrinicpalName"=$member.UserPrincipalName
}) > $null
}
}
If you wanna search for a specific group you can use -SearchString 'groupName' or a list of groups:
$groups='group1,group2,group3'.split(',')|%{
Get-AzureADGroup -SearchString $_
}

How To fix "add-member : Cannot add a member with the name "" because a member with that name already exists"

I need to list multiple FTP connexion on LogicApp service and export this list on csv file. This export is use for see if the SSL protocol connexion is activate or not. My script generate this error.
add-member : Cannot add a member with the name "FTP" because a member with that name already exists. To overwrite the member anyway, add the Force parameter to your command.
LogicApp FTP connexion :
https://learn.microsoft.com/en-us/azure/connectors/connectors-create-api-ftp
I need to add these FTP connections in this format on excel :
format need
$LogicApp_temp = $null
$LogicApp_obj = #()
$LogicApp_temp = new-object PSObject
$FTPAll = Get-AzResource -ResourceGroupName $RG -ResourceType Microsoft.Web/connections
foreach ( $FTPAlls in $FTPAll ) {
$FTPName = $FTPAlls.name
$FTPName1 = Get-AzResource -ResourceGroupName $RG -ResourceType Microsoft.Web/connections -Name $FTPName
foreach ($FTPName2 in $FTPName1) {
$FTPcheckType = $FTPName2.Properties.api.name
if ( $FTPcheckType -eq "ftp") {
$FTPSSL1 = $FTPName1.Properties.parameterValues.isSSL
}
else {
}
$LogicApp_temp | add-member -MemberType NoteProperty -Name "FTP" -Value "$FTPName2.Properties.displayName $FTPSSL1"
}
}
$LogicApp_obj += $LogicApp_temp
Write-Output "LogicApp Name : $Name Ressource Group : $RG OK"
# CSV Exports :
$LogicApp_obj | Export-Csv $csvPath -Append -NoTypeInformation
thank you in advance for your help
Because the PSObject property just could be set one value at one time, if you use the -Force, it will overwrite the value before.
If you want to get the .csv file like the format you provided, we could just append every string like joyftp True first.
My working sample:
$RG = "<resource group name>"
$LogicApp_obj = #()
$value = ""
$FTPAll = Get-AzResource -ResourceGroupName $RG -ResourceType Microsoft.Web/connections
foreach ( $FTPAlls in $FTPAll ) {
$FTPName = $FTPAlls.name
$FTPName1 = Get-AzResource -ResourceGroupName $RG -ResourceType Microsoft.Web/connections -Name $FTPName
foreach ($FTPName2 in $FTPName1) {
$FTPcheckType = $FTPName2.Properties.api.name
$displayname = $FTPName2.Properties.displayName
$LogicApp_temp = New-Object -TypeName PSObject
if ( $FTPcheckType -eq "ftp") {
$FTPSSL1 = $FTPName1.Properties.parameterValues.isSSL
$value += "$displayname $FTPSSL1 | "
$LogicApp_temp | add-member -MemberType NoteProperty -Name "FTP" -Value "$value" -Force
}
}
}
Write-Output "LogicApp Name : $Name Ressource Group : $RG OK"
# CSV Exports :
$LogicApp_temp | Export-Csv -Path "C:\Users\joyw\Desktop\ftp.csv" -NoTypeInformation
The .csv file:

Retrieve azure blob metadata with Powershell

How do I retrieve the metadata of a blob folder's contents (such as name, size etc) with powershell and export it as CSV?
Assume you have azure powershell az module installed(also you can change the code accordingly if you are using AzureRm module).
There are 2 methods:
Method 1: Use PSCustomObject. Sample code as below:
$accountname="xxx"
$accountkey="xxx"
$ctx = New-AzStorageContext -StorageAccountName $accountname -StorageAccountKey $accountkey
$myblobs = Get-AzStorageBlob -Container "aa1" -Context $ctx
$Output = $myblobs | ForEach-Object {
[PSCustomObject]#{
"Name" = $_.Name
"Length" =$_.Length
}
}
$Output | Export-Csv "d:\temp\test2.csv" -NoTypeInformation
Method 2: Use psobject. Sample code as below, save the generated file to location "d:\temp\test2.csv":
$accountname="xxx"
$accountkey="xxx"
$ctx = New-AzStorageContext -StorageAccountName $accountname -StorageAccountKey $accountkey
$myblobs = Get-AzStorageBlob -Container "aa1" -Context $ctx
$i=0
foreach($b in $myblobs)
{
$i++
if($i -eq 1)
{
$obj = New-Object psobject
$obj | add-member -membertype NoteProperty -name "Name" -value $b.name
#the length unit is byte
$obj | add-member -membertype NoteProperty -name "Length" -value $b.length
$obj | Export-Csv "d:\temp\test2.csv" -NoTypeInformation
}
else
{
$obj = New-Object psobject
$obj | add-member -membertype NoteProperty -name "Name" -value $b.name
$obj | add-member -membertype NoteProperty -name "Length" -value $b.length
$obj | Export-Csv "d:\temp\test2.csv" -NoTypeInformation -Append
}
}
Test result as below:

Resources