loop through azure objects and filter them on tags - azure

I have a question , recently we started using Tagging in Azure and needed to list specific object by thier Tags. Below is the script used to find the resources. in both cases we find a specific object in the results when using match and notmatch. This is strange behaviour when searching Tagged resources. what other ways do you use to complete the task?
PS C:\WINDOWS\system32> $KeyName = 'Department'
PS C:\WINDOWS\system32> $NewKeyValue = "PROD, Data"
PS C:\WINDOWS\system32> $AzSqlServer = Get-AzSqlServer
PS C:\WINDOWS\system32> if($AzSqlServer)
>> {
>> foreach ($server in $AzSqlServer )
>> {
>> $SQLDatabase = Get-AzSqlDatabase -ServerName $server.ServerName -ResourceGroupName $server.ResourceGroupName| Where-Object {$_.tags.Values -notmatch "PROD, Data"}
>> write-output $SQLDatabase.DatabaseName
>> }
>> }
DBname1
DBname2
DBname3
DBname4
master
master
master
**DBname5**
PS C:\WINDOWS\system32>
PS C:\WINDOWS\system32> $KeyName = 'Department'
PS C:\WINDOWS\system32> $NewKeyValue = "PROD, Data"
PS C:\WINDOWS\system32> $AzSqlServer = Get-AzSqlServer
PS C:\WINDOWS\system32> if($AzSqlServer)
>> {
>> foreach ($server in $AzSqlServer )
>> {
>> $SQLDatabase = Get-AzSqlDatabase -ServerName $server.ServerName -ResourceGroupName $server.ResourceGroupName| Where-Object {$_.tags.Values -match "PROD, Data"}
>> write-output $SQLDatabase.DatabaseName
>> }
>> }
**DBname5**

The problem here is with unexpected results of using -notmatch and -match operators against a list. Switching to -notcontains and -contains for exact matches will produce the desired result.
$AzSqlServer = Get-AzSqlServer
if ($AzSqlServer) {
foreach ($server in $AzSqlServer) {
$SQLDatabase = Get-AzSqlDatabase -ServerName $server.ServerName -ResourceGroupName $server.ResourceGroupName |
Where-Object {$_.tags.Values -notcontains "PROD, Data"}
$SQLDatabase.Databasename
}
}
When using -notcontains, a list's items are compared in their entirety. The list will only return true if there are no items that match the target item. When using -notmatch against a list, the list's items that do not match the target item are returned. Any returned item results in a True result in a boolean statement. Below is a simplified example of your experience:
# Notice how both boolean statements return True
PS> 1,2,3 -notmatch 2
1
3
PS> [bool](1,2,3 -notmatch 2)
True
PS> 1,2,3 -match 2
2
PS> [bool](1,2,3 -match 2)
True
# Now using -notcontains and -contains
PS> 1,2,3 -notcontains 2
False
PS> 1,2,3 -contains 2
True

Related

Powershell - Export Count of Groups Members to excel

foreach ($group in $ADMSObjects){
$searchString = $group.GroupDisplayName
$count = (Get-AzureADGroup -All $true -SearchString "$searchString" | Get-AzureADGroupMember -ALL 1).COUNT
write-host $group.GroupDisplayName , $count
}
I just need the function 'extended' to actually export $group.GroupDisplayName and $count to an Excel Sheet.
When I try to do something like:
foreach ($group in $ADMSObjects){
$searchString = $group.GroupDisplayName
$count = (Get-AzureADGroup -All $true -SearchString "$searchString" | Get-AzureADGroupMember -ALL 1).COUNT
write-host $group.GroupDisplayName , $count
Export-Csv -Path $path $group, $count -Append
}
DLAS - AMER - Global Planning and Transformation - 1190-GO-CGPT10026 32
Export-Csv : Cannot convert 'System.Object[]' to the type 'System.Char' required by parameter
'Delimiter'. Specified method is not supported.
At C:\users\crxdan\Documents\Set-DLASGroups.ps1:220 char:36
+ Export-Csv -Path $path $group, $count -Append
+ ~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Export-Csv], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.ExportCsvCommand
I'm not really sure where to go from here.
you could use PSCustomObject to get your results in an order. I guess the $group you mentioned is group display name. I do not have an environment to test it. so please test it from your end. Thanks!
$result = foreach ($group in $ADMSObjects){
$searchString = $group.GroupDisplayName
$count = (Get-AzureADGroup -All $true -SearchString "$searchString" | Get-AzureADGroupMember -ALL 1).COUNT
write-host $group.GroupDisplayName , $count
[PSCustomObject]#{
Group = $group.GroupDisplayName
Count = $Count
}
}
$result | Export-Csv -Path $path -Append
I tried to reproduce the scenario in my environment:
Note: To print display name:
Run using $group.DisplayName
Used below code:
$azgroups=Get-AzureADGroup
foreach ($group in $azgroups){
$searchString = $group.GroupDisplayName
$count = (Get-AzureADGroup -All $true -SearchString "$searchString" | Get-AzureADGroupMember -ALL 1).COUNT
write-host $group.DisplayName , $count
$group_properties = [pscustomobject] #{
"DisplayName" = $group.DisplayName
"Count" = $count
}
$group_properties | Export-csv -Path C:\User\xxx\myexcelsheet" -NoTypeInformation -Force -Append
}
The csv or excel file is created successfully:
And we could see the required fiels in the csv file

How to split different values in powershell by a line

With this script i am able to fetch all the Tags that a VM has but i want that in output the each key and its value should be separated by a line in the way that each key and its value appears on different lines like this
reference image
# Sign into Azure Portal
connect-azaccount
# Fetch the Virtual Machines from the subscription
$azureVMDetails = get-azvm
# Fetch the NIC details from the subscription
$azureNICDetails = Get-AzNetworkInterface | ?{ $_.VirtualMachine -NE $null}
#Fetching Virtual Machine Details
$virtual_machine_object = $null
$virtual_machine_object = #()
#Iterating over the NIC Interfaces under the subscription
foreach($azureNICDetail in $azureNICDetails){
#Fetching the VM Name
$azureVMDetail = $azureVMDetails | ? -Property Id -eq $azureNICDetail.VirtualMachine.id
#Fetching the VM Tags
foreach($azureDetail in $azureVMDetails) {
$vm_tags = $azureVMDetail| Select-Object -Property (
#{name='Tags'; expression = {($_.tags.GetEnumerator().ForEach({ '{0} : {1}' -f $_.key, $_.value }) -join ';')}}
)
}
#VM Details export
$virtual_machine_object_temp = new-object PSObject
$virtual_machine_object_temp | add-member -membertype NoteProperty -name "name" -Value $azureVMDetail.Name
$virtual_machine_object_temp | add-member -membertype NoteProperty -name "comments" -Value ($vm_tags.Tags -join ';')
$virtual_machine_object += $virtual_machine_object_temp
}
#Report format and path
$virtual_machine_object | Export-Csv "C:\Users\JOHN\Desktop\Inventory\Final Scripts\VM_details_$(get-date -f dd.MM.yyyy).csv" -NoTypeInformation -Force
I tried to reproduce the same in my environment and got the results successfully by using the below PowerShell script:
$vmdeatil = Get-AzVm -Name testvm | Select -ExpandProperty Tags
$value = $vmdeatil
foreach($i in 0..($value.Count -1))
{
$ErrorActionPreference = ‘SilentlyContinue’
[array]$report += [pscustomobject] #{
key = $key[$i]
name = $value[$i]
}
}
$report | Export-Csv -Path "C:\Users\ruk1.csv" -NoTypeInformation
Response:
The output is successfully exported in the csv file like below:

Powershell export CSV looks weird

I have an issue with my CSV export to Excel with powershell. When I import it looks like pretty bad and I can't find any information that helps me to solve it.
Here I attach an image of the import and the code. I see other CSV imports and it looks normal with its categories spaced by rows in Excel, but I don't know how to do it.
Image of my workbook
$Computers = Get-ADComputer -Filter {OperatingSystem -like "*Server*"} -Properties OperatingSystem | Select-Object -ExpandProperty Name
Foreach($computer in $computers){
if(!(Test-Connection -Cn $computer -BufferSize 16 -Count 1 -ea 0 -quiet))
{write-host "cannot reach $computer offline" -f red}
else {
$outtbl = #()
Try{
$sr=Get-WmiObject win32_bios -ComputerName $Computer -ErrorAction Stop
$Xr=Get-WmiObject –class Win32_processor -ComputerName $computer -ErrorAction Stop
$ld=get-adcomputer $computer -properties Name,Lastlogondate,operatingsystem,ipv4Address,enabled,description,DistinguishedName -ErrorAction Stop
$r="{0} GB" -f ((Get-WmiObject Win32_PhysicalMemory -ComputerName $computer |Measure-Object Capacity -Sum).Sum / 1GB)
$x = gwmi win32_computersystem -ComputerName $computer |select #{Name = "Type";Expression = {if (($_.pcsystemtype -eq '2') )
{'Laptop'} Else {'Desktop Or Other something else'}}},Manufacturer,#{Name = "Model";Expression = {if (($_.model -eq "$null") ) {'Virtual'} Else {$_.model}}},username -ErrorAction Stop
$t= New-Object PSObject -Property #{
serialnumber = $sr.serialnumber
computername = $ld.name
Ipaddress=$ld.ipv4Address
Enabled=$ld.Enabled
Description=$ld.description
Ou=$ld.DistinguishedName.split(',')[1].split('=')[1]
Type = $x.type
Manufacturer=$x.Manufacturer
Model=$x.Model
Ram=$R
ProcessorName=($xr.name | Out-String).Trim()
NumberOfCores=($xr.NumberOfCores | Out-String).Trim()
NumberOfLogicalProcessors=($xr.NumberOfLogicalProcessors | Out-String).Trim()
Addresswidth=($xr.Addresswidth | Out-String).Trim()
Operatingsystem=$ld.operatingsystem
Lastlogondate=$ld.lastlogondate
LoggedinUser=$x.username
}
$outtbl += $t
}
catch [Exception]
{
"Error communicating with $computer, skipping to next"
}
$outtbl | select Computername,enabled,description,ipAddress,Ou,Type,Serialnumber,Manufacturer,Model,Ram,ProcessorName,NumberOfCores,NumberOfLogicalProcessors,Addresswidth,Operatingsystem,loggedinuser,Lastlogondate |export-csv -Append C:\temp\VerynewAdinventory.csv -nti
}
}
As commented, your locale computer uses a different delimiter character that Export-Csv by default uses (that is the comma).
You can check what character your computer (and thus your Excel) uses like this:
[cultureinfo]::CurrentCulture.TextInfo.ListSeparator
To use Export-Csv in a way that you can simply double-click the output csv file to open in Excel, you need to either append switch -UseCulture to it, OR tell it what the delimiter should be if not a comma by appending parameter -Delimiter followed by the character you got from the above code line.
That said, your code does not produce the full table, because the export to the csv file is in the wrong place. As Palle Due commented, you could have seen that if you would indent your code properly.
Also, I would advise to use more self-describing variable names, so not $r or $x, but $memory and $machine for instance.
Nowadays, you should use Get-CimInstance rather than Get-WmiObject
AND adding to an array with += should be avoided as it is both time and memory consuming. (on every addition to an array, which is of fixed size, the entire array has to be rebuilt in memory).
Your code revised:
# set the $ErrorActionPreference to Stop, so you don't have to add -ErrorAction Stop everywhere in the script
# remember the currens value, so you can restore that afterwards.
$oldErrorPref = $ErrorActionPreference
$ErrorActionPreference = 'Stop'
# get an array of computers, gathering all properties you need
$computers = Get-ADComputer -Filter "OperatingSystem -like '*Server*'" -Properties OperatingSystem, LastLogonDate, IPv4Address, Description
$result = foreach ($computer in $computers) {
$serverName = $computer.Name
if(!(Test-Connection -ComputerName $serverName -BufferSize 16 -Count 1 -ErrorAction SilentlyContinue -Quiet)) {
Write-Host "cannot reach $serverName offline" -ForegroundColor Red
continue # skip this computer and proceed with the next one
}
try {
# instead of Get-WmiObject, nowadays you should use Get-CimInstance
$bios = Get-WmiObject -Class Win32_bios -ComputerName $serverName
$processor = Get-WmiObject -Class Win32_Processor -ComputerName $serverName
$memory = Get-WmiObject -Class Win32_PhysicalMemory -ComputerName $serverName
$disks = Get-WmiObject -Class Win32_LogicalDisk -ComputerName $serverName
$machine = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $serverName |
Select-Object #{Name = "Type"; Expression = {
if ($_.pcsystemtype -eq '2') {'Laptop'} else {'Desktop Or Other something else'}}
},
Manufacturer,
#{Name = "Model"; Expression = {
if (!$_.model) {'Virtual'} else {$_.model}}
},
UserName
# output an object to be collected in variable $result
# put the properties in the order you would like in the output
[PsCustomObject] #{
ComputerName = $serverName
Enabled = $computer.Enabled
Description = $computer.description
IpAddress = $computer.IPv4Address
Ou = $computer.DistinguishedName.split(',')[1].split('=')[1]
Type = $machine.type
SerialNumber = $bios.serialnumber
Manufacturer = $machine.Manufacturer
Model = $machine.Model
Ram = '{0} GB' -f (($memory | Measure-Object Capacity -Sum).Sum / 1GB)
ProcessorName = $processor.Name
NumberOfCores = $processor.NumberOfCores
NumberOfLogicalProcessors = $processor.NumberOfLogicalProcessors
Addresswidth = $processor.Addresswidth
OperatingSystem = $computer.OperatingSystem
# {0:N2} returns the number formatted with two decimals
TotalFreeDiskSpace = '{0:N2} GB' -f (($disks | Measure-Object FreeSpace -Sum).Sum / 1GB)
LoggedInUser = $machine.UserName
Lastlogondate = $computer.LastLogonDate
}
}
catch {
Write-Warning "Error communicating with computer $serverName, skipping to next"
}
}
# restore the ErrorActionPreference to its former value
$ErrorActionPreference = $oldErrorPref
# output the completed array in a CSV file
# (using the delimiter characer your local machine has set as ListSeparator)
$result | Export-Csv -Path 'C:\temp\VerynewAdinventory.csv' -UseCulture -NoTypeInformation

Using Objects in Powershell to do command

What im trying to do is the following:
Im getting a list of all VM`s that have some set values such as being in use and NOT having Azure Benefits turned on.
What i have is that i made a tiny script to get all machines within an subscription and select on the basis mentioned above.
What i want to do with that output is do the command Update-azureVM in bulk.
Could someone help me with this ? do i need to export the values to an excel and use that sheet to do a bulk update-AzureVM
here is the code that i have setup at the moment:
$returnObj = #()
$VMs=Get-AzVm -status
foreach ($VM in $VMs)
{
$obj = New-Object psobject -Property #{
"VmSize" = $VM.HardwareProfile.VmSize;
"VmName" = $vm.Name;
"PowerState" = $vm.PowerState;
"License_Type" = $vm.LicenseType;
}
$returnObj += $obj | select VmSize, VmName, PowerState, License_Type
}
$returnObj |
Where-Object{$_.PowerState -ne "VM deallocated"} |
Where-Object{$_.License_Type -ne "Windows_Server"} |
Where-Object{$_.License_Type -ne "Windows_Client"} |
Export-Csv C:\temp\freek.csv
Thank you all in advance!

Compiling data into columns to be exported to CSV/excel

I am writing a short script to inventory all servers in our infrastructure, this used to be done manually which means some servers may show up as active in our SQL DB but is actually offline, or vice versa.
What i want to do is query our vCenter, SQL and AD and then compiling the result into a csv to be viewed in Excel (see pic ) http://imgur.com/NnwEM4H
Now here is my question: How do i add the columns and format this properly? I want a seperate row for each servername which means sometimes that row will be a blank/empty in one or more of the columns. The Refrence list will always contain a servername though.
I've tried the following:
$ServerList = #()
foreach ($p in $RefList)
{
$Server = New-Object System.Object
$Server | Add-Member -MemberType NoteProperty -Name RefrenceList -Value $p.Name
$ServerList += $Server
}
foreach ($s in $VMList)
{
$Server = New-Object System.Object
$Server | Add-Member -MemberType NoteProperty -Name vCenter -Value $s.name
$ServerList += $Server
}
Which doesnt create the vCenter column or add any data to it.
I also asked over at reddit/r/powershell and tried the following, which unfortently doesn't work either:
$ServerList = #()
foreach ($p in $RefList)
{
$Server = New-Object System.Object
$Server | Add-Member -MemberType NoteProperty -NameRefrenceList -Value $p.Name
$ServerList += $Server
}
Foreach ($server in $serverlist)
{
if ($vmlist -contains $server)
{
$server | add-member -MemberTypeNoteProperty -Name VMList -Value $Server
}
}
I'm at a loss here, i can't even get the first 2 columns to work..
Any advice i greatly appriceiated
First build the List will all Noteproperties :
$ServerList = $reflist | select Name, SQL,SCCM, AD, VCenter #as needed.
Now you can easily update the fields with your foreach Statements.
foreach ($server in $ServerList)
{
if ($vmlist -contains $server)
{
$Server.VCenter = $Server.Name
}
if ($sqllist -contains $server)
{
$Server.SQL = $Server.Name
}
#....
}
and so on with your other lists.

Resources