How to add foreach-object -parallel output to a dictionary/arraylist - powershell

I'm trying to get all the stale branches from Azure DevOps to nag the developers to remove them.
If I use this script below, I get all the results I want, but it takes ages to process.
$resultlist = New-Object System.Collections.ArrayList
function Get-StaleBranches {
$dateString = (Get-Date).AddDays(-90).ToString("MM/dd/yyyy HH:mm:ss")
$date = [datetime]::parseexact($dateString, 'MM/dd/yyyy HH:mm:ss', $null)
$reposArray | ForEach-Object {
$repo = $PSItem
$refsUri = "url"
$refs = (Invoke-RestMethod -Uri $refsUri -Method get -Headers $AzureDevOpsAuthenicationHeader).value
foreach($branch in $refs){
$splitName = $branch.name.Substring(11)
$commitUri = $using:OrgUri + "url"
$commits = (Invoke-RestMethod -Uri $commitUri -Method get -Headers $AzureDevOpsAuthenicationHeader).value
$commitDate = [datetime]::parseexact($commits.author.date, 'MM/dd/yyyy HH:mm:ss', $null)
if($commitDate -lt $date -and $splitName -notlike "develop" -and $splitName -notlike "release" -and $splitName -notlike "master")
{
$result = #{}
$result.repo = $repo
$result.branch = $splitName
$result.date = $commitDate
$result.author = $commits.author.name
$result.email = $commits.author.email
$resultlist.Add((New-Object PsObject -Property $result)) | Out-Null
}
}
}
}
Get-StaleBranches
To speed it up, I tried using the foreach-object -parallel functionality like this:
$threadSafeDictionary = [System.Collections.Concurrent.ConcurrentDictionary[string,object]]::new()
function Get-StaleBranches {
$dateString = (Get-Date).AddDays(-90).ToString("MM/dd/yyyy HH:mm:ss")
$date = [datetime]::parseexact($dateString, 'MM/dd/yyyy HH:mm:ss', $null)
$reposArray | ForEach-Object -Parallel {
$dict = $using:threadSafeDictionary
$repo = $PSItem
$dict.$repo = #()
$refsUri = "url"
$refs = (Invoke-RestMethod -Uri $refsUri -Method get -Headers $using:AzureDevOpsAuthenicationHeader).value
foreach($branch in $refs){
$splitName = $branch.name.Substring(11)
$commitUri = "url"
$commits = (Invoke-RestMethod -Uri $commitUri -Method get -Headers $using:AzureDevOpsAuthenicationHeader).value
$commitDate = [datetime]::parseexact($commits.author.date, 'MM/dd/yyyy HH:mm:ss', $null)
if($commitDate -lt $using:date -and $splitName -notlike "develop" -and $splitName -notlike "release" -and $splitName -notlike "master")
{
$dict.$repo += [PSCustomObject]#{
Branch = $splitName
Date = $commitDate
Author = $commits.author.name
Email = $commits.author.email
}
}
}
}
}
Get-StaleBranches
However, now all branches in the dictionary are doubled. Did I make a mistake somewhere? Is there any other way to approach this?
Any help will be appreciated.

I have no explanation for your symptom, but I recommend simplifying your code as follows, which will also speed it up:
Avoid the explicit use of (synchronized) data structures and instead let PowerShell collect loop output in an array for you, as described in this answer, which works with any command output (and therefore also with ForEach-Object [-Parallel] and a foreach loop statement).
The following simplified example shows how to do that:
function Get-StaleBranches {
# Implicitly output what the ForEach-Object -Parallel script block outputs.
(1..5).ForEach({ 'repo' + $_ }) | ForEach-Object -Parallel {
# Create and implicitly output a custom object for each repo.
[pscustomobject] #{
Repo = $PSItem
Results = foreach ($branch in (1..3).ForEach({ 'branch' + $_ })) {
# Create and implicitly output a custom object; all such objects
# created in this `foreach` loop are collected in the .Results property.
[pscustomobject] #{
Branch = $branch
Date = Get-Date
}
}
}
}
}
Note:
Calling Get-StaleBranches outputs a stream of (nested) [pscustomobject] instances, which, when captured in a variable, become an [object[]] array.
Display output:
Repo Result
---- ------
repo1 {#{Branch=branch1; Date=2/6/2023 11:53:33 AM}, #{Branch=branch2; Date=2/6/2023 11:53:33 AM}, #{Branch=branch3; Date=2/6/2023 11:53:33 AM}}
repo2 {#{Branch=branch1; Date=2/6/2023 11:53:33 AM}, #{Branch=branch2; Date=2/6/2023 11:53:33 AM}, #{Branch=branch3; Date=2/6/2023 11:53:33 AM}}
repo3 {#{Branch=branch1; Date=2/6/2023 11:53:33 AM}, #{Branch=branch2; Date=2/6/2023 11:53:33 AM}, #{Branch=branch3; Date=2/6/2023 11:53:33 AM}}
repo4 {#{Branch=branch1; Date=2/6/2023 11:53:33 AM}, #{Branch=branch2; Date=2/6/2023 11:53:33 AM}, #{Branch=branch3; Date=2/6/2023 11:53:33 AM}}
repo5 {#{Branch=branch1; Date=2/6/2023 11:53:33 AM}, #{Branch=branch2; Date=2/6/2023 11:53:33 AM}, #{Branch=branch3; Date=2/6/2023 11:53:33 AM}}
This isn't the same as returning a dictionary keyed by branch names, but it isn't hard to adapt the solution to do that:
$dict = #{} # initialize output dictionary (hashtable)
Get-StaleBranches |
ForEach-Object {
# Create an entry for the repo at hand.
$dict[$_.Repo] = $_.Results
}
# Output the resulting dictionary.
$dict
Display output (the Name column contains the dictionary's key values):
Name Value
---- -----
repo4 {#{Branch=branch1; Date=2/6/2023 12:01:42 PM}, #{Branch=branch2; Date=2/6/2023 12:01:42 PM}, #{Branch=branch3; Date=2/6/2023 12:01:42 PM}}
repo2 {#{Branch=branch1; Date=2/6/2023 12:01:42 PM}, #{Branch=branch2; Date=2/6/2023 12:01:42 PM}, #{Branch=branch3; Date=2/6/2023 12:01:42 PM}}
repo5 {#{Branch=branch1; Date=2/6/2023 12:01:42 PM}, #{Branch=branch2; Date=2/6/2023 12:01:42 PM}, #{Branch=branch3; Date=2/6/2023 12:01:42 PM}}
repo3 {#{Branch=branch1; Date=2/6/2023 12:01:42 PM}, #{Branch=branch2; Date=2/6/2023 12:01:42 PM}, #{Branch=branch3; Date=2/6/2023 12:01:42 PM}}
repo1 {#{Branch=branch1; Date=2/6/2023 12:01:42 PM}, #{Branch=branch2; Date=2/6/2023 12:01:42 PM}, #{Branch=branch3; Date=2/6/2023 12:01:42 PM}}

Related

PowerShell & Power BI Rest API

Essentially what I'm after is the results of rest API Gateways - Get Datasource Users but retaining the ID (in this example $Line.id from my imported CSV file).
The end result should be a CSV with the following fields -
ID, emailAddress, datasourceAccessRight, displayName, identifier, principalType
I'm new to PowerShell and surprised I got this far but can't figure out this final bit.
Cheers
$webclient=New-Object System.Net.WebClient
$webclient.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
$Dir = "C:\pbi_pro_user_logs\"
Login-PowerBI
$GateWayFile = Import-CSV -Path "C:\pbi_pro_user_logs\Gateway_Detail.csv"
$Output = #()
foreach ($Line in $GateWayFile){
$Item = $Line.id
$url = "https://api.powerbi.com/v1.0/myorg/gateways/HIDDEN/datasources/"+$Item+"/users"
$Output += (Invoke-PowerBIRestMethod -Url $url -Method Get | ConvertFrom-Json)
}
$Result = $Output.value
$Result | Export-Csv $Dir"GateWay_users.csv" -NoTypeInformation
Try this, using a calculated property from Select-Object:
$GateWayFile = Import-CSV -Path "C:\pbi_pro_user_logs\Gateway_Detail.csv"
$Output = Foreach ($Line in $GateWayFile){
$url = "https://api.powerbi.com/v1.0/myorg/gateways/HIDDEN/datasources/"+$Line.id+"/users"
$Item = (Invoke-PowerBIRestMethod -Url $url -Method Get | ConvertFrom-Json)
# output all properties of the item, plus the ID:
$ItemWithID = $Item | Select *,#{l='Id';e={$line.id}}
Write-Output $ItemWithID
}
# This depends on how you want your csv structured, but for example:
$Result = $Output | Select Id,Value
Or, if Value is a whole object that ID should be assigned inside of, then change the selection lines:
$ItemWithID = $Item.Value | Select *,#{l='Id';e={$line.id}}
$Result = $Output

Powershell Calculated Property - Calling HashTable enumerator?

I'm unable to display the calculated property column called Logon Type which is translated from a hash table.
The script below is working fine, but I just need to translate the raw value number into a more meaningful description.
function Get-LogonEvents {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[Alias('ServerName', 'Server', 'Name')]
[string[]]$ComputerName,
[Parameter(ValueFromPipelineByPropertyName = $true, Mandatory = $true)]
[PSCredential]$Credential,
[Parameter()]
[ValidateSet("Service", "Interactive", "RemoteInteractive", "NetworkCleartext", "CachedInteractive", "Unlock", "NewCredentials", "Network", "*")]
[string[]]$LogonType = #("Interactive", "RemoteInteractive", "CachedInteractive"),
[string]$UserName,
[Parameter()]
[switch]$Oldest,
[Parameter()]
[int64]$MaxEvents,
[Parameter()]
[datetime]$StartTime = (Get-Date 1/1/1900),
[Parameter()]
[datetime]$StopTime = (Get-Date 1/1/2100)
)
Begin {
Function ParseEventMessage {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline = $true)]
$obj
)
Begin {
$defaultDisplaySet = 'TimeCreated', 'MachineName', 'TargetDomainName', 'TargetUserName'
$defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet(‘DefaultDisplayPropertySet’, [string[]]$defaultDisplaySet)
$PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]#($defaultDisplayPropertySet)
$myHash = #{ }
}
Process {
([xml]($obj.ToXml())).event.eventdata.data | ForEach-Object { $myHash[$PSItem.name] = $PSItem.'#text' }
New-Object -TypeName PSObject -Property $myHash | ForEach-Object {
$PSItem.PSObject.TypeNames.Insert(0, "EventLogRecord.XMLParse")
$PSItem | Add-Member MemberSet PSStandardMembers $PSStandardMembers -PassThru |
Add-Member -MemberType NoteProperty -Name TimeCreated -Value $obj.timecreated -PassThru |
Add-Member -MemberType NoteProperty -Name MachineName -Value $obj.MachineName -PassThru
}
}
}
$hashLogonType = #{
"Interactive" = "2"
"Network" = "3"
"Service" = "5"
"Unlock" = "7"
"NetworkCleartext" = "8"
"NewCredentials" = "9"
"RemoteInteractive" = "10"
"CachedInteractive" = "11"
}
$filter = #"
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">
*[System[
(EventID='4624')
and TimeCreated[#SystemTime>='{0}' and #SystemTime<='{1}']
]
and EventData[
Data[#Name='LogonType'] and ({2})
{3}
]
]
</Select>
</Query>
</QueryList>
"#
}
Process {
foreach ($obj in $ComputerName) {
if ($UserName) {
$joinUserName = "and Data[#Name='TargetuserName'] and (Data='{0}')" -f $UserName
}
$joinLogonType = ($LogonType | ForEach-Object { $hashLogonType[$PSItem] }) -replace '^', "Data='" -replace '$', "'" -join " or "
$objFilter = $filter -f (Get-Date $StartTime -Format s), (Get-Date $StopTime -Format s), $joinLogonType, $joinUserName
$hashEventParm = #{
ComputerName = $obj
FilterXml = $objFilter
}
if ($Credential) { $hashEventParm['Credential'] = $Credential }
if ($MaxEvents) { $hashEventParm['MaxEvents'] = $MaxEvents }
$objFilter | Write-Verbose
Get-WinEvent #hashEventParm | ParseEventMessage
}
}
End { }
}
$TargetDomainNameException = #('Window Manager','Font Driver Host')
$exceptionRegex = $TargetDomainNameException -join "|"
Get-LogonEvents -ComputerName 'Localhost' -MaxEvents 10 |
Where-Object { ($_.TargetDomainName -notmatch $exceptionRegex) } |
Select-Object WorkstationName,
TargetUserName,
TargetDomainName,
Type,
LogonType,
#{n ='LogonType'; e={$hashLogonType[[string]$_.LogonType]}},
#{n = 'Logon Type'; e = {$hashLogonType["$($_.LogonType)"]}},
ProcessName,
IPAddress,
#{n="Host Name"; e={([System.Net.Dns]::GetHostByAddress($_.IPaddress).Hostname)}},
TimeCreated |
Out-GridView
Error:
I have modifiedthe Calculated property like:
#{n = 'Logon Type'; e = {$hashLogonType["$($_.LogonType)"]}},
Somehow it is still not displaying the column "Logon Type", however, the raw value on LogonType column still showing as 10, 3 ,etc...?
I see two problems.
$hashLogonType is defined inside the function and won't be available in the global scope.
The keys for $hashLogonType are by [string] not by [int].
If you're able to modify the original function, you might consider adding a property where the string value of LogonType is saved.
Otherwise, keep a copy of $hashLogonType in your variable scope with integers as keys, and base your calculated property on that.
The easiest way to get what you want is to create your own hash table and use it in your pipeline.
# Create a hash table for your own use in your variable scope.
$myHashTable = #{
2 = "Interactive"
3 = "Network"
5 = "Service"
7 = "Unlock"
8 = "NetworkCleartext"
9 = "NewCredentials"
10 = "RemoteInteractive"
11 = "CachedInteractive"
}
# Shim object.
$exampleObject = [PSCustomObject]#{
LogonType = 2
WorkstationName = "myHost.example.com"
}
# Modify your pipeline to use your hash table.
$exampleObject |
Select-Object -Property WorkstationName, LogonType, #{label="Logon Title";expression={$myHashTable[$_.LogonType]}}
PS> ./Answer 02.ps1
WorkstationName LogonType Logon Title
--------------- --------- -----------
myHost.example.com 2 Interactive
In principle, it is possible to modify the original function. But, I don't have any data to test with. Maybe Doug can help. He seems to have access to an event log.
You would have to do two things.
Add a hash table with integer keys in scope for ParseEventMessage(). For example, add the hash table to ParseEventMessage()'s Begin block.
Where it says
Add-Member -MemberType NoteProperty -Name MachineName -Value $obj.MachineName -PassThru
Add another property by extending that pipeline:
Add-Member -MemberType NoteProperty -Name LogonTitle -Value {$myHashTable[$_.LogonType]} -PassThru
Edit: Yes Mike is absolutely correct, the hashtable was defined inside the get-logonevents function and not used. I've moved it out and now it should work.
I think you should reverse the assignment of the hashtable. Either as an int or a string should work then. I did it like this and it worked fine.
function Get-LogonEvents {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[Alias('ServerName', 'Server', 'Name')]
[string[]]$ComputerName,
[Parameter(ValueFromPipelineByPropertyName = $true, Mandatory = $true)]
[PSCredential]$Credential,
[Parameter()]
[ValidateSet("Service", "Interactive", "RemoteInteractive", "NetworkCleartext", "CachedInteractive", "Unlock", "NewCredentials", "Network", "*")]
[string[]]$LogonType = #("Interactive", "RemoteInteractive", "CachedInteractive"),
[string]$UserName,
[Parameter()]
[switch]$Oldest,
[Parameter()]
[int64]$MaxEvents,
[Parameter()]
[datetime]$StartTime = (Get-Date 1/1/1900),
[Parameter()]
[datetime]$StopTime = (Get-Date 1/1/2100)
)
Begin {
Function ParseEventMessage {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline = $true)]
$obj
)
Begin {
$defaultDisplaySet = 'TimeCreated', 'MachineName', 'TargetDomainName', 'TargetUserName'
$defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet(‘DefaultDisplayPropertySet’, [string[]]$defaultDisplaySet)
$PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]#($defaultDisplayPropertySet)
$myHash = #{ }
}
Process {
([xml]($obj.ToXml())).event.eventdata.data | ForEach-Object { $myHash[$PSItem.name] = $PSItem.'#text' }
New-Object -TypeName PSObject -Property $myHash | ForEach-Object {
$PSItem.PSObject.TypeNames.Insert(0, "EventLogRecord.XMLParse")
$PSItem | Add-Member MemberSet PSStandardMembers $PSStandardMembers -PassThru |
Add-Member -MemberType NoteProperty -Name TimeCreated -Value $obj.timecreated -PassThru |
Add-Member -MemberType NoteProperty -Name MachineName -Value $obj.MachineName -PassThru
}
}
}
$filter = #"
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">
*[System[
(EventID='4624')
and TimeCreated[#SystemTime>='{0}' and #SystemTime<='{1}']
]
and EventData[
Data[#Name='LogonType'] and ({2})
{3}
]
]
</Select>
</Query>
</QueryList>
"#
}
Process {
foreach ($obj in $ComputerName) {
if ($UserName) {
$joinUserName = "and Data[#Name='TargetuserName'] and (Data='{0}')" -f $UserName
}
$joinLogonType = ($LogonType | ForEach-Object { $hashLogonType[$PSItem] }) -replace '^', "Data='" -replace '$', "'" -join " or "
$objFilter = $filter -f (Get-Date $StartTime -Format s), (Get-Date $StopTime -Format s), $joinLogonType, $joinUserName
$hashEventParm = #{
ComputerName = $obj
FilterXml = $objFilter
}
if ($Credential) { $hashEventParm['Credential'] = $Credential }
if ($MaxEvents) { $hashEventParm['MaxEvents'] = $MaxEvents }
$objFilter | Write-Verbose
Get-WinEvent #hashEventParm | ParseEventMessage
}
}
End { }
}
$hashLogonType = #{
2 = "Interactive"
3 = "Network"
5 = "Service"
7 = "Unlock"
8 = "NetworkCleartext"
9 = "NewCredentials"
10 = "RemoteInteractive"
11 = "CachedInteractive"
}
$TargetDomainNameException = #('Window Manager','Font Driver Host')
$exceptionRegex = $TargetDomainNameException -join "|"
Get-LogonEvents -ComputerName 'Localhost' -MaxEvents 10 -OutVariable LogonEvents |
Where-Object { ($_.TargetDomainName -notmatch $exceptionRegex) } |
Select-Object WorkstationName,
TargetUserName,
TargetDomainName,
Type,
#{n="LogonType";e={$hashLogonType.[int]$_.logontype}},
ProcessName,
IPAddress,
#{n="Host Name"; e={([System.Net.Dns]::GetHostByAddress($_.IPaddress).Hostname)}},
TimeCreated |
Out-GridView

how to export powershel result to csv

I want to export what I already filtered in ForEach-Object. The problem is that I can't export the filtered data.
I tried the following:
$getTapes.rows | Export-Csv C:\\123\\123456.txt but this has exported all the information without filter.
$getTapes = Invoke-RestMethod -Method GET -ContentType $content -Uri $Uri -Headers #{'Authorization' = $Authorization}
$today = Get-Date
$getTapes.rows | ForEach-Object {
$tape = $_;
if ( $tape.custom_fields.Ueberschreibschutz.value -ge $today ) {
Write-Host "Treffer ID=" $tape.asset_tag " Name=" $tape.name " SNR=" $tape.serial " Mediensatz=" $tape.custom_fields.Mediensatz.value
}
}
$getTapes.rows |export-Csv C:\\123\\123456.txt
I expect:
Treffer ID= 1 Name= 12 SNR= 12345 Mediensatz= M
Treffer ID= 2 Name= 32 SNR= 54321 Mediensatz= W
You should not use Write-Host to collect data. That's only to output pixels on the screen. Instead you should create a custom object you can use as you want later on ... like this:
$Result = $getTapes.rows | ForEach-Object {
if ( $_.custom_fields.Ueberschreibschutz.value -ge $today ) {
[PSCustomObject]#{
TrefferID = $_.asset_tag
Name = $_.name
SNR = $_.serial
Mediensatz = $_.custom_fields.Mediensatz.value
}
}
}
$Result | Export-Csv -Path C:\123\123456.csv -NoTypeInformation
Write-host do nothing except it shows you the result in the console, so it will not modify or delete the things you don't want in $getTapes.rows.
Instead you can define a variable $result and iterate over the $getTapes.rows using Foreach-Object, and add the result if it meets your if condition.
Try this:
$getTapes = Invoke-RestMethod -Method GET -ContentType $content -Uri $Uri -Headers #{'Authorization' = $Authorization}
$today = Get-Date
$getTapes.rows | ForEach-Object -begin {$result = "" } {
$tape = $_;
if ( $tape.custom_fields.Ueberschreibschutz.value -ge $today ) {
$result += "Treffer ID= $($tape.asset_tag) Name= $($tape.name) SNR= $($tape.serial) Mediensatz= $($tape.custom_fields.Mediensatz.value)`n"
}
} -end {$result | export-Csv C:\123\123456.txt}

Writing the output of Get-NetTCPConnection to an array - no output

I am trying to write the values of the PowerShell cmdlet Get-NetTCPConnection to an array but nothing is being written to the list.
$list= #()
$outputs = Get-NetTCPConnection
foreach ($output in $outputs) {
$obj = New-Object PSObject -Property #{
TheLocalAddress = "EMPTY"
TheLocalPort = "EMPTY"
TheRemoteAddress = "EMPTY"
TheRemotePort = "EMPTY"
}
$obj.TheLocalAddress = $output.LocalAddress
$obj.TheLocalPort = $output.LocalPort
$obj.TheRemoteAddress = $output.RemoteAddress
$obj.TheRemotePort = $output.RemotePort
$list += $obj
}
$list
If the prefix The isn't required for the properties, why not use
$list = Get-NetTCPConnection | Select-Object LocalAddress,LocalPort,RemoteAddress,RemotePort
Or a more efficient [PSCustomObject] ?
$list = foreach ($Conn in Get-NetTCPConnection) {
[PSCustomObject]#{
TheLocalAddress = $Conn.LocalAddress
TheLocalPort = $Conn.LocalPort
TheRemoteAddress = $Conn.RemoteAddress
TheRemotePort = $Conn.RemotePort
}
}
$list

Looping through a CSV column using powershell [duplicate]

This question already has answers here:
Read Column data from CSV
(1 answer)
Read a Csv file with powershell and capture corresponding data
(3 answers)
Closed 7 years ago.
I have a CSV file like below
Data,Name,Age
Test,T1,22
Test2,T2,23
Test3,T3,24
I want to do some processing like this
Foreach(header in CSvFile.Headers)
{
//Loop through the column data
}
EDIT : Displaying what I am looking for in real code.
Add-PSSnapin "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue
$SiteUrl = "http://www.dev.com"
$Web = Get-SPWeb $SiteUrl
$description = "Group with contribute access."
$permissionLevel = "Contribute"
foreach($groupName in **CSV.Headers**)
{
$web.SiteGroups.Add($groupName, $web.SiteUsers["Test\data"], $web.SiteUsers["Test\data"], $description)
$group = $web.SiteGroups[$groupName]
$loc = Get-Location
$Users = "Test\data"
$roleAssignment = new-object Microsoft.SharePoint.SPRoleAssignment($group)
$roleDefinition = $web.Site.RootWeb.RoleDefinitions[$permissionLevel]
$roleAssignment.RoleDefinitionBindings.Add($roleDefinition)
$web.RoleAssignments.Add($roleAssignment)
$web.Update()
foreach ($User in **groupName.columnData**) {
$Web.EnsureUser($User)
Set-SPUser -Identity $User -Web $SiteUrl -Group $group
}
}
$Web.Dispose();
Can some one please tell me how to achieve this in powershell.
Thanks
How about something like this:
$csvPath = "C:\temp\temp.csv"
$csv = Import-CSV $csvPath
$csvHeaders = ($csv | Get-Member -MemberType NoteProperty).name
foreach($header in $csvHeaders) {
...etc...