I'm trying to put objects in a hashtable. I'm not getting errors but cannot access the data.
$Level1Hashtable = #{}
$Level2Object = New-Object System.Object
$Level2Object | Add-Member -MemberType NoteProperty -Name Name -Value "abc"
$Level2Object | Add-Member -MemberType NoteProperty -Name IpAddress -Value "192.168.1.1"
$Level1Hashtable.Add("Test1",$Level2Object)
$Level2Object = New-Object System.Object
$Level2Object | Add-Member -MemberType NoteProperty -Name Name -Value "123"
$Level2Object | Add-Member -MemberType NoteProperty -Name IpAddress -Value "192.168.1.1"
$Level1Hashtable.Add("Test2",$Level2Object)
$Level1Hashtable.Test1.IpAddress
This kind of redundant instantiation doesn't really impress me, so I went a slightly different route:
$Servers =
#{
"DC1" = [pscustomobject]#{ FQDN = "dc1.ad.foobar.com"; IpAddress = "192.168.2.1"}
"DC2" = [pscustomobject]#{ FQDN = "dc2.ad.foobar.com"; IpAddress = "192.168.2.2"}
"STS" = [pscustomobject]#{ FQDN = "sts.ad.foobar.com"; IpAddress = "192.168.2.3"}
}
Then you can also access elements very easily:
Servers["DC1"].IpAddress = "192.168.2.4"
Tested on PowerShell Core (aka PowerShell 6), works like a charm. Cheers.
That works for me using V4. Running in V2 it doesn't work, but does if I switch from using System.Object to PSObject for the object type in the New-Object cmdlets.
$Level1Hashtable = #{}
$Level2Object = New-Object PSObject
$Level2Object | Add-Member -MemberType NoteProperty -Name Name -Value "abc"
$Level2Object | Add-Member -MemberType NoteProperty -Name IpAddress -Value "192.168.1.1"
$Level1Hashtable.Add("Test1",$Level2Object)
$Level2Object = New-Object PSObject
$Level2Object | Add-Member -MemberType NoteProperty -Name Name -Value "123"
$Level2Object | Add-Member -MemberType NoteProperty -Name IpAddress -Value "192.168.1.1"
$Level1Hashtable.Add("Test2",$Level2Object)
$Level1Hashtable.Test1.IpAddress
Depending on the version of PowerShell you're using Add-Member had an issue (v1 and maybe v2) where you had to use -PassThru and reassign to the original object e.g.:
$Level2Object = $Level2Object | Add-Member NoteProperty Name abc -PassThru
In V3 you can create this more simply like so:
$Level2Object = [pscustomobject]#{Name='abc';IpAddress='192.168.1.1'}
In V2 you can use the Property parameter on new-object to simplify as well:
$Level2Object = new-object psobject -property #{Name='abc';IpAddress='192.168.1.1'}
Related
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:
function Get-vmstatus {
# 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) {
$azureVMDetail = $azureVMDetails | ? -Property Id -eq $azureNICDetail.VirtualMachine.id
$vm_status = get-azvm -ResourceGroupName $azureVMDetail.resourcegroupname -name $azureVMDetail.name -Status
$vm_tags = ($azureVMDetail.Tags.values) -join ';'
$vmsize = Get-AzVMSize -VMName $azureVMDetail.Name -ResourceGroupName $azureVMDetail.ResourceGroupName | ? { $_.Name -eq $azureVMDetail.HardwareProfile.VmSize }
$OsDisksize = $azureVMDetail.StorageProfile.OsDisk.DiskSizeGB
#Fetching the private IP
$private_ip_address = ($azureNICDetail.IpConfigurations | select-object -ExpandProperty PrivateIpAddress) -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 "VCPUs" -Value $vmsize.NumberOfCores
$virtual_machine_object_temp | add-member -membertype NoteProperty -name "Status" -Value $vm_status.Statuses[1].DisplayStatus
$virtual_machine_object_temp | add-member -membertype NoteProperty -name "Memory" -Value $vmsize.MemoryInMB
$virtual_machine_object_temp | add-member -membertype NoteProperty -name "Disk" -Value $OsDisksize
$virtual_machine_object_temp | add-member -membertype NoteProperty -name "Comments" -Value $vm_tags
$virtual_machine_object += $virtual_machine_object_temp
}
$virtual_machine_object | Export-Csv "C:\Users\mouj\Desktop\Inventory\Final Scripts\VM_details_$(get-date -f dd.MM.yyyy).csv" -NoTypeInformation -Force
}
After running the script the Status of the Azure VMs are shown as VM running, VM stopped, VM deallocated. Now i want to replace the VM running with "Active" and VM stopped, VM deallocated with "Offline". How can i do with conditional statement or is there any other way to do it ? Thanks in advance
Use Add-Member to add a ScriptProperty - a dynamic property that can reference the value(s) of other properties on the object:
$virtual_machine_object_temp | Add-Member -MemberType ScriptProperty -Name State -Value { if($_.Status -eq 'Running'){ 'Active' }else{ 'Offline' } }
Now, whenever you look at the new State property, it will resolve to Active whenever the Status property is Running, otherwise Offline
I'm interested in querying the pipeline consumption report that is available from the Data Factory monitor. Is there a table on Log Analytics or PowerShell cmdlet that would return this information? I checked the ADFv2 PowerShell module but couldn't find any. My goal is to aggregate the information available in this report to identify what are the most costly pipelines.
reference: https://techcommunity.microsoft.com/t5/azure-data-factory/new-adf-pipeline-consumption-report/ba-p/1394671
Thank you
Doing more research someone pointed me to a GitHub page where the product team posted a PowerShell script to find part of what I was looking for {1}. So I did some modifications to the script to have the output that I needed. With the output below I can extract the values from the MS calculator to get an estimated cost for each pipeline run. {2}
$startTime = "21/6/2021 7:00:00"
$endTime = "21/6/2021 10:00:00"
$adf = '<data factory name>'
$rg = '<resrouce group name>'
$outputObj = #()
$pipelineRuns = Get-AzDataFactoryV2PipelineRun -ResourceGroupName $rg -DataFactoryName $adf -LastUpdatedAfter $startTime -LastUpdatedBefore $endTime
# loop through all pipelines and child activities to return billable information
foreach ($pipelineRun in $pipelineRuns) {
$activtiyRuns = Get-AzDataFactoryV2ActivityRun -ResourceGroupName $rg -DataFactoryName $adf -pipelineRunId $pipelineRun.RunId -RunStartedAfter $startTime -RunStartedBefore $endTime
foreach ($activtiyRun in $activtiyRuns) {
if ($null -ne $activtiyRun.Output -and $null -ne $activtiyRun.Output.SelectToken("billingReference.billableDuration")) {
$obj = #()
$obj = $activtiyRun.Output.SelectToken("billingReference.billableDuration").ToString() | ConvertFrom-Json
$obj | Add-Member -MemberType NoteProperty -Name activityType -value $activtiyRun.Output.SelectToken("billingReference.activityType").ToString()
$obj | Add-Member -MemberType NoteProperty -Name pipelineName -value $pipelineRun.PipelineName
$obj | Add-Member -MemberType NoteProperty -Name activtiyRuns -value $activtiyRuns.Count
$outputObj += $obj
}
else {}
}
}
# output aggregated result set as table
$groupedObj = $outputObj | Group-Object -Property pipelineName, activityType, meterType
$groupedObj | ForEach-Object {
$value = $_.name -split ', '
New-Object psobject -Property #{
activityType = $value[1];
meterType = $value[2];
pipelineName = $value[0];
executionHours = [math]::Round(($_.Group | Measure-object -Property duration -sum).Sum, 4)
orchestrationActivityRuns = $groupedObj.group.activtiyRuns[0]
}
} | Sort-Object -Property meterType | Format-Table
Output sample:
Consumption report from the Data Factory monitor
reference:
https://github.com/Azure/Azure-DataFactory/tree/main/SamplesV2/PastRunDetails#simple-script-that-prints--activity-level-run-details-in-45-day-range {1}
https://azure.microsoft.com/en-us/pricing/calculator/?service=data-factory%2F {2}
I have multiple files contain a persons Fullname in a single cell. I would like to separate these names into two columns - first name and Surname
the code I have used to separate values worked in a previous iteration of the script I had but now no longer works
I can't pinpoint where the error lies, can anyone advise?
$path = 'C:\MAY2019correct'
#XYZ
$excelOut = Join-Path -Path $path -ChildPath 'XYZ.csv'
$completedFile = Join-Path -Path $path -ChildPath 'Completed-XYZ.csv'
$defaultValue = 'ABC'
$filter = '*XYZ*'
$excelFile = Get-ChildItem -Path $path -Filter $filter -File |
Select-Object -First 1
$allstaff = #()
if ($excelFile) {
$excel = New-Object -ComObject Excel.Application -Property #{Visible =
$false}
# Open the file
$workbook = $excel.Workbooks.Open($excelFile.FullName)
# Activate the first worksheet
$sheet = $workbook.Sheets.Item(1)
[void]$sheet.Cells.Item(1, 1).EntireRow.Delete() # Delete the first row
[void]$sheet.Cells.Item(1, 1).EntireRow.Delete() # Delete the 2 row
[void]$sheet.Cells.Item(1, 1).EntireRow.Delete() # Delete the 3 row
$workbook.SaveAs($excelOut,6)
# Close workbook and save changes
$workbook.Close($true)
# Quit Excel
$excel.Quit()
# clean-up Com objects
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($sheet) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbook) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel) | Out-Null
$headers = 'Element Name','Surname','EmployeeNo','Amount','YTD'
# import the csv file and select all the above headers plus one that is created using a calculated property
$csv = Import-Csv -Path $excelOut -Header $headers -UseCulture | Select-Object *, #{Name = 'Paycentre'; Expression = {$defaultValue}}|
Write-Host "Creating completed csv file '$completedFile'"
$csv | Export-Csv -Path $completedFile -UseCulture -Force -
NoTypeInformation
}
else {
Write-Warning "Could not find a file using filter '$filter' in path
'$path'"
}
foreach($staff in $completedFile)
{
#Get the values from the CSV for this row
$Surname = $staff.Surname
$Surname = $Surname.Substring(0, $Surname.lastIndexOf(' '))
$Initial = $staff.Surname
$Initial = $Initial.Substring($Initial.lastIndexOf(' ') + 1 )
$Firstname = $staff.Surname
$Firstname = $Firstname.Substring($Initial.lastIndexOf(' ') + 1 )
$EmployeeNo = $staff.EmployeeNo
$NINumber = $staff.NINumber
$Amount = $staff.Amount
$Paycentre = $staff.Paycentre
$staff2 = New-Object System.Object
$staff2 | Add-Member -MemberType NoteProperty -Name "Surname" -Value $Surname
$staff2 | Add-Member -MemberType NoteProperty -Name "FirstName" -Value $Firstname
$staff2 | Add-Member -MemberType NoteProperty -Name "EmployeeNo" -Value $EmployeeNo
$staff2 | Add-Member -MemberType NoteProperty -Name "NINumber" -Value $NINumber
$staff2 | Add-Member -MemberType NoteProperty -Name "Amount" -Value $Amount
$staff2 | Add-Member -MemberType NoteProperty -Name "FirstName" -Value $Initial
$staff2 | Add-Member -MemberType NoteProperty -Name "Paycentre" -Value $Paycentre
#add to array
$allstaff += $staff2
}
$allstaff | Export-Csv -NoTypeInformation -Path $completedFile
The first thing I see is that your foreach loop is iterating over the $completedFile variable which appears to be a file path, not a collection.
Should it be foreach ($staff in $csv) instead?
Also, be very wary of dealing with names in code. It's super easy to make poor assumptions that break things. See Falsehoods Programmers Believe About Names for more info there.
Why does the script below come up with the following error?
"Add-Member : Cannot process command because of one or more missing
mandatory parameters: InputObject.
+ $obj = Add-Member <<<< -MemberType NoteProperty -Name ComputerName -Value $ComputerName
+ CategoryInfo : InvalidArgument: (:) [Add-Member], ParameterBindingException
+ FullyQualifiedErrorId : MissingMandatoryParameter,Microsoft.PowerShell.Commands.AddMemberCommand"
Script
# Receives the computer name and stores the required results in $obj.
Function WorkerNetworkAdaptMacAddress {
Param($ComputerName)
$colItems = GWMI -cl "Win32_NetworkAdapterConfiguration" -name "root\CimV2" -comp $ComputerName -filter "IpEnabled = TRUE"
$obj = New-Object -TypeName PSobject
ForEach ($objItem in $colItems)
{
$obj = Add-Member -MemberType NoteProperty -Name ComputerName -Value $ComputerName
$obj = Add-Member -MemberType NoteProperty -Name MacAddress -Value $objItem.MacAddress
$obj = Add-Member -MemberType NoteProperty -Name IPAdress -Value $objitem.IpAddress
}
Write-Output $obj
}
# Receives the computer name and passes it to WorkerNetworkAdaptMacAddress.
Function Get-NetworkAdaptMacAddress {
begin {}
process{
WorkerNetworkAdaptMacAddress -computername $_
}
end {}
}
# Passes a computer name to get-networkAdaptMacAddress
'tbh00363' | Get-NetworkAdaptMacAddress
You need to move the PSObject creation into the loop. Otherwise, you'll get errors that the properties already exist on the object.
Secondly, you need to tell Add-Member on which object to operate. You do it either by piping the object to the cmdlet or by specifying it on the InputObject parameter. Finally, return the object back to the pipeline by specifying the PassThru switch on the last Add-Member call:
ForEach ($objItem in $colItems)
{
$obj = New-Object -TypeName PSobject
Add-Member -InputObject $obj -MemberType NoteProperty -Name ComputerName -Value $ComputerName
Add-Member -InputObject $obj -MemberType NoteProperty -Name MacAddress -Value $objItem.MacAddress
Add-Member -InputObject $obj -MemberType NoteProperty -Name IPAddress -Value $objitem.IpAddress -PassThru
}
Alternatively, you could simplify the process with New-Object's -Property parameter:
Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $ComputerName -Filter "IpEnabled=TRUE" | Foreach-Object {
New-Object -TypeName PSobject -Property #{
ComputerName=$ComputerName
MacAddress=$_.MacAddress
IPAddress=$_.IpAddress
}
}
Or by using Select-Object:
Get-WmiObject ... | Select-Object #{n='ComputerName';e={$_.__SERVER}},MacAddress,IpAddress
First you need to specify the input object to which the property should be added by piping it to the Add-Member cmdlet.
Then, if you want the cmdlet to return the modified object, you should invoke it with the -PassThru argument:
When you use the PassThru parameter, Add-Member returns the
newly-extended object. Otherwise, this cmdlet does not generate any
output.
Here's a slightly modified version of your script:
$obj = $objItem | Add-Member -MemberType NoteProperty -Name ComputerName -Value $ComputerName -PassThru
However, since in your case you don't really need to save the output object in a new variable, you could also simply say:
$obj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $ComputerName
Try like this:
$objcol = #()
ForEach ($objItem in $colItems)
{
$obj = New-Object System.Object
$obj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $ComputerName
$obj | Add-Member -MemberType NoteProperty -Name MacAddress -Value $objItem.MacAddress
$obj | Add-Member -MemberType NoteProperty -Name IPAdress -Value $objitem.IpAddress
$objcol += $obj
}
Write-Output $objcol
As indicated by Enrico, Shay and Christian, you should specify the object on which Add-Member operates, either by piping the object to Add-Member or by explicitly specifying the object on the InputObject parameter. When adding multiple members using Add-Member I usually add the PassThru switch to avoid repeating the InputObject and to provide a visual cue.
ForEach ($objItem in $colItems) {
$obj = New-Object PSobject
$obj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $ComputerName -PassThru `
| Add-Member -MemberType NoteProperty -Name MacAddress -Value $objItem.MacAddress -PassThru `
| Add-Member -MemberType NoteProperty -Name IPAdress -Value $objitem.IpAddress -PassThru
}
You're assigning the result of Add-Member to a variable, not adding it to a property collection within $obj.
Instead of
$obj = Add-Member -MemberType NoteProperty -Name ComputerName -Value $ComputerName
Try this:
Add-Member -MemberType NoteProperty -Name ComputerName -Value $ComputerName -inputObject $obj