fetch particular column in PowerShell - powershell

I am creating a PowerShell Script wherein I have a csv file which consist of few parameters wherein there is a parameter called as status .The ask is whenever the status is Fail ,I want to get the corresponding row. I am using Import-Csv cmdlet in order to fetch the csv file and checking the status if the status is fail or not and based on that I am fetching the corresponding details using the split function but when I am using the split method it is giving me error as
Method invocation failed because
[System.Management.Automation.PSCustomObject] does not contain a
method named 'split'.
Using the below code
$Report=(Import-Csv "C:\Users\Documents\Optim_Config_Report_20210216170900.csv")
foreach($i in $Report)
{
if($i.Status -eq "Fail")
{
$RULE_ID= $i.split(',')[0]
Write-output $RULE_ID
}
}
Can someone please help me how can I get the corresponding Row details for which the Status is fail?
Report is something like this in a csv format
Rule,Id,Category,Sub_Category,System_Value,Risk,Status
1,Operations,Access,Login,High,Pass
2,Operations,Logging,AccessControl,Medium,Pass
3,Operations,encryptions,certificate,High,Fail,
4,Security,Encryption,protcolo,High,Fail
Thanks in Advance!

When you Import-CSV, you are creating an array of [PSCustomObject]s, each of which has properties corresponding to the names of the columns in the CSV. For your example, those properties will be Rule, ID, Category, Sub_Category, System_Value, Risk, and Status.
It is not clear from your example what information you wish to report in the event of a status of Fail, but all you need to do is reference the properties that contain that information - for example, if I wanted to report the Category and Sub_Category, I might use
...
if ($i.status -eq "Fail") {
Write-Host $i.Category, $i.Sub_Category
}
...
Which would, for your sample data, output
encryptions certificate
Encryption protcolo

For a CSV file named "test.csv" with content like this:
"Rule","Id","Category","Sub_Category","System_Value","Risk","Status"
1,Operations,Access,Login,1,High,Pass
2,Operations,Logging,AccessControl,1,Medium,Pass
3,Operations,encryptions,certificate,1,High,Fail
4,Security,Encryption,protcolo,1,High,Fail
This script:
Import-Csv -Path ./test.csv | Where-Object Status -eq Fail | Format-Table
Returns:
Rule Id Category Sub_Category System_Value Risk Status
---- -- -------- ------------ ------------ ---- ------
3 Operations encryptions certificate 1 High Fail
4 Security Encryption protcolo 1 High Fail

Related

PowerShell script to get distribution group report

I am looking for a PowerShell script to get a export Distribution Group with following Information.
Group Display Name
Group Owner
Group Member
Last Activity Date
Member Count
Received Email Count
Group ID
I am working on a script but it is returning error
$groupmembers = foreach ($i in Get-DistributionGroup)
{
Get-DistributionGroupMember $i | select Display Name, #{n='Member';e={$i.DisplayName}}
}
Get-DistributionGroupMember returns an object of type ReducedRecipient which does not contain a fields called Display or Name - but it does contain a field called DisplayName - i think this is probably your issue.
If you dont want to read the docs, an easy way of seeing the members of an object is to use ConvertTo-Json. Temporarily add the line Get-DistributionGroupMember $i | ConvertTo-Json inside your foreach loop above the command that is failing. It will output the entire ReducedRecipient Object in JSON format so you can easily read the available property names and their current values.

Is there a way to put a counter column when doing Get commands in PowerShell?

I need to extract a Get command results into a CSV. The order column should be automatically generated upon a call and give each object its counter upon its appearance in the list. Would this be possible?
For example, when I'd do something like
Get-VMHost | Select #{N="Order";E={$suborder++}}, Name, Version, Build | Export-Csv -path .\smth.csv
I would like to get a result like
Order Name Version Build
----- ---- ------- -----
1 servername1 1.1.1 11111111
2 servername2 1.1.1 11111111
3 servername3 1.1.1 11111111
Would this be possible without using an array?
There are two problems with the current approach:
Unary ++ doesn't output anything by default
Select-Object runs property expressions in their own scope, so you're not actually updating $suborder, you're creating a new local variable every time.
The first problem can be solved by wrapping the operation in the grouping operator (...):
... | Select #{N="Order";E={($suborder++)}}, ...
The second problem can be solved by obtaining a reference to an object that exposes the suborder value as a property.
You can either use a hashtable or a custom object to "host" the counter:
$counter = #{ suborder = 1 }
... | Select #{N="Order";E={($counter['suborder']++)}}
... or you can make PowerShell wrap the original variable in a PSRef-wrapper by using the [ref] keyword:
$suborder = 1
... | Select #{N="Order";E={(([ref]$suborder).Value++)}}

Get the Data values from the registry using powershell

I am trying to add an application in 'DisallowRun' registry key to avoid running application to specific users. Need to add the application if not exist. Consider 'TestApp3.exe' in this case.
Used below query to get the list of items in the key. It is giving Name(Key Name), Property(Name Value : Data Value)
Get-Item -Path "Registry::HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\DisallowRun"
Output
Name Property
---- --------
DisallowRun 1 : TestApp1.exe
DisallowRun 2 : TestApp2.exe
DisallowRun 3 : TestApp3.exe
DisallowRun 4 : TestApp4.exe
When i use .Property in the code, getting only Name Values and not Data Values
(Get-Item -Path "Registry::HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\DisallowRun").Property
Output
1
2
3
4
If i get only the Data Values (similar to below) then i could have use contains function to check the specific application is already available or not. Please help me to get only Data Value or is there anyway to check the application is exist in the registry key.
TestApp1.exe
TestApp2.exe
TestApp3.exe
TestApp4.exe
Try this out.
(Get-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\DisallowRun).PSObject.Properties | Where-Object {
$_.Name -notmatch "^PS"
} | Select-Object -ExpandProperty Value
Try Get-ItemProperty -Path Registry::HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\DisallowRun

Powershell: Checking for duplicate email in AD

Background:
I'm trying to make a script that will see if a new users email ($email) is the same as one already existing (which would cause an error). I have a very remedial understanding of objects so this is what I have so far (yes it is ugly):
$email = "smithj#company.com"
$mailcheck = Get-ADUser -filter * -Properties * | ForEach-Object {$_.mail}
$mailcheck | ForEach-Object {if ($email -eq $_.mail){"$email = $($_.mail) - Matching email"}else{"$email = $($_.mail) - No duplicate email"}}
Problem 1:
The script doesn't match emails. When I have a matching email in AD it doesn't recognize it.
Problem 2: When executing just the 2nd line, indexing doesn't work properly. While it looks like a consecutive list of emails, if a user doesn't have an email at all (blank) really it could be something like this:
smithj#company.com
johnsonj#company.com
robertsr#company.com
doej#company.com
So $mailcheck[0] returns smithj#company.com while $mailcheck[1] returns blank despite the list actually looking like this:
smithj#company.com
johnsonj#company.com
robertsr#company.com
doej#company.com
Conclusion: I really just need problem 1 solved but problem 2 peaked my curiosity. Thanks.
The way you are doing it above is really inefficient. -Properties * will return every property on the user, some properties are expensive in terms of processing power to return. Only use the properties you need. The properties returned by default without specifying that parameters do not need to be specified with -Properties, only additional nondefault properties. -Filter * will also match on literally any value for any field, effectively returning every ADUser, further increasing the resources required for your script to execute as you will now have to process every user to find any accounts matching that email.
Now that that's out of the way, here is a more efficient method to implement what you're asking:
# Set the email address to search for
$emailAddress = 'box#domain.tld'
# Get all users where the email address matches what is set above
# Force it as an array so you can treat it like one even if only
# one or zero users are returned
$adUsers = #( Get-ADUser -Filter "EmailAddress -eq '${emailAddress}'" )
# Make sure no accounts were returned
# If there are, throw an error with the number of users and who they are
if( $adUsers ) {
throw "Found $($adUsers.Count) users matching EmailAddress ${emailAddress}: $($adUsers.SamAccountName -join ', ')"
}
By using the filter to only match the specific email address, Powershell does not need to collect every single AD user in the system, or iterate over all of them to find a specific email address. This will take a long time to check, especially in larger environments, whereas filtering the returned objects based on email address (or on any other property) results in a faster operation and less data to sift through.
You can then check whether $adUsers contains anything (an array count of anything but 0 evaluates to $True, you could also use if( $adUsers.Count -gt 0 ) as the condition), and if so, throw an error with more information as I do above.
Update for comment question:
To answer your other question in the comment, "I didn't know what object to compare $email to", EmailAddress and Mail both look to be valid properties, but I don't know the difference between them. In my environment, both Mail and EmailAddress are populated with my email address, but have always used EmailAddress and haven't run into issues using that. Maybe one is deprecated and the other is new or something, but I'm not really sure.
There is also yet another property called proxyAddresses as well, which preliminary research shows that both EmailAddress and Mail are related to it, but I don't know much about it. It's not populated on my ADUser objects, so I can't poke around with it.

How can I create a table in powershell using variables and data I input

I'm trying to do something like this (tried to make it look like a table, but wasn't working with markdown,html or bunch of spaces):
Column1
Location info
Location #
Location name
Location phone
Location address
Column2
[blank]
1
NYC
789-987-1234
12 Some Blvd
Column3
Network info
Location Octet
External IP
Some other IP
More Ips
Column4
[blank]
345
10.89.52.468
10.346.345.1
10.326.345.2
I've tried creating new objects, converting arrays/hash to csv and then back and I'm having no luck. I've read some other threads but they all incorporate the use of cmdlets that create objects already and just working with that. I thought convert from csv did that, and it does I think, but how Im converting it back may be off. The above table is thus 6 columns and 5 rows, the top row having column 2 and 4 being blank.
I'd really like to learn how to do this, since I'll probably be employing it for other tasks as well.
I believe you are trying to achieve something like this? :
$col1=#("Location info","Location #","Location name","Location phone","Location address");
$col2=#("","1","NYC","789-987-1234","12 Some Blvd");
$col3=#("Network info","Location Octet","External IP","Some other IP","More Ips");
$col4=#("","345","10.89.52.468","10.346.345.1","10.326.345.2");
$hash=#{"Column1"=$col1;"Column2"=$col2;"Column3"=$col3;"Column4"=$col4};
$obj = New-Object PSObject -Property $hash
$obj|Format-Table -Wrap -AutoSize
You will get the data as you've specified. You can use -ExpandProperty "Column1" (e.g. if you want to expand on all it's values). You can use ConvertTo-Html if you like to create a html-table of the data.
However, I would consider structuring the data in another fasion. How about keeping this data in seperate objects instead of formatting it in this way?
You could e.g. have a set of objects with the properties representing what you want.
E.g. objects having the representative data :
$obj = new-object PSObject -Property #{"Location info"="My loc"; "Location #"="My location"}
$obj2 = new-object PSObject -Property #{"Location info"="My loc2"; "Location #"="My location2"}
$myLocations = #($obj,$obj2);
That'd be more representative, and you could play and format the $myLocations for the properties you'd want.