Accessing data retuned by PowerShell Import-CSV - csv

I am trying to write a PowerShell script that uses a CSV file as input that will turn off the clutter feature in Office 365. The CSV file has only 1 column and that has the 2 target email addresses that I am using for testing. When I run this script with a read-host line and enter a valid email address it works with no errors. When I use the CSV file errors follow.
Import-Module MSOnline
$LiveCred = Get-Credential
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/PowerShell -Credential $LiveCred -Authentication Basic -AllowRedirection
Import-PSSession -allowclobber $Session
Connect-MsolService -Credential $LiveCred
cd c:\scripts
Write-Host "This tool removes the Clutter feature from O365 "
$Clutter = Import-Csv .\Clutteroff.csv
foreach ($user in $Clutter){
Set-Clutter -Identity $User -Enable $false
}
When I run this I get the following error :
Cannot process argument transformation on parameter 'Identity'. Cannot convert value "#{UserID=xxxxx#myCompany.com}" to type "Microsoft.Exchange.Configuration.Tasks.MailboxIdParameter". Error: "Cannot
convert hashtable to an object of the following type: Microsoft.Exchange.Configuration.Tasks.MailboxIdParameter. Hashtable-to-Object conversion is not supported in restricted language mode or a Data
section."
+ CategoryInfo : InvalidData: (:) [Set-Clutter], ParameterBindin...mationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,Set-Clutter
+ PSComputerName : ps.outlook.com
Any help would be appreciated and explanations will get extra credit :)
CSV file = User, XXXX#MyCompany.com, YYYY#MyCompany.com
Email addresses are valid.

Putting all of the items in one line like that is not going to work well with Import-CSV. Import-CSV is suited to a table structure (columns and rows), whereas you are just using a comma-separated list (one row, with an unknown number of columns). If in fact you do have the items on different lines, then please correct the question and I'll change the answer.
To work with the data from a file formatted like that, I would just split it into an ArrayList, and remove the first item because it is "User" and not not an email address:
[System.Collections.ArrayList]$Clutter = (get-content .\Clutteroff.csv).split(",")
$Clutter.RemoveAt(0)
Then you can iterate through the array:
foreach ($user in $Clutter){
$address = $user.trim()
{Set-Clutter -Identity $address -Enable $false}
}
For the extra credit, $user in your script was returning a row of key/value pairs to represent columns (keys) and the data in the columns (values). Your error message shows #{UserID=xxxxx#myCompany.com}, so to return just the email address you would use $user.UserID to return the value for UserID.

i GOT THIS WORKING TO PULL FROM CSV SO ONLY THOSE USERS ARE MODIFIED!! SORRY FOR THE CAPS BUT I AM A TOTAL NOOB AND I COULDNT BELIEVE I GOT THIS TO WORK!!! I am beyond STOKED!! :)
the csv requires no headers, just the email address of the users you want to modify in one column
$Clutter = (Get-Content "pathofyourcsv.csv")
foreach ($User in $Clutter) {
$address = $User
Get-Mailbox -Identity $User | Set-Clutter -Enable $false}

Related

Results of multiple foreach loops in one table in PowerShell

I have multiple results of a foreach and I need to stick them into a table.
My current result is:
The user Johnny is a trainer
The user Mark is a trainer
The user Bob is a footballer
The user fred is a footballer
The user Moe is a footballer
This comes from the foreach loops:
foreach ($user in $trainer)
{
Write-Host "The user $user.Name is a $user.Type"
#For email $body+= "The user " + $user.Name + " is a " + $user.Type +"<br/>"
}
And it goes on for all the types foreach ($user in $footballers),....
What I'm trying to achieve is to have a nice table sent to me by mail that looks kinda like this:
How can I add results to a table from multiple for each loops in PowerShell?
Your code as written won't work correctly actually, you need to be using the sub-expression operator $() as follows in order to access the object properties:
Write-Host "The user $($user.Name) is a $($user.Type)"
It seems that $trainer is already an object with Name and Type properties so (outside of the foreach loop) it should be a simple case of doing:
$Body = $trainer | Select Name,Type | ConvertTo-HTML
Send-MailMessage -Body $Body -BodyAsHtml # other parameters, e.g to/from
Also if you have multiple objects that have the same properties, you could just combine them first with the addition operator:
$athlete = $trainer + $footballer

powershell: compare specific columns of CSV files and return entire row of differences

I have 2 CSV files I'd like to compare. They both have multiple columns of different data but they also both have a column with IP addresses. Call them $log1 and $log2
I am trying to compare the files. If an IP from $log1 is found in $log2 I would like an output file that has the entire row of data from the match of $log2...
When I use:
Compare-Object -Property 'IP address' -ReferenceObject $log1 -DifferenceObject $log2
It returns only the 'IP address' column and the SideIndicator.
I think I'm barking up the wrong tree here, can anyone offer some advice?
I would try another approach :
$log1,$log2 | group-object -Property 'IP address' | where {$_.count -eq 2}
In the result you will find a group property with the two lines.
"Try adding the -PassThru flag to your command."
- Dave Sexton
This works. I exported the results to CSV and sorted by the SideIndicator when I opened the file (don't think you can get PS to sort by SideIndicator).
Thanks Dave.
There's probably more ways to accomplish this, as noted by others but this achieved my goal.
This script will compare your both csv files and writhe output for each double ip address found.
#import your csv files
$csv1 = Import-Csv "C:\Users\Admin\Desktop\csv\csv1.csv"
$csv2 = Import-Csv "C:\Users\Admin\Desktop\csv\csv2.csv"
#Compare both csv files (.ip corresponds to your column name for your ip address in the csv file )
$compare = Compare-Object $csv1.ip $csv2.ip -IncludeEqual | ? {$_.SideIndicator -eq "=="}
if ($compare) {
foreach ($ip in $compare.InputObject) {
Write-Output "IP $ip exist in both csv files"
}
}
Else
{
Write-Output "Double ip not found"
}

Powershell: How to throw an error if a CSV entry is blank

I've written an extensive script that runs through an AD termination process, and the script can obtain the necessary information from a CSV. How do I make it so that it errors out if the entry is blank in the CSV? I've tried putting in Try-Catch, If-Else, everything that I know how to do. I've tried changing the error action, and I can get it to throw system generated errors (ex. "Cannot bind parameter "Identity" to the target..."), but I cannot get it to do what I want. Please see the code example below:
(Yes, I know that I'm duplicating values. This of importance later on in the script, and not the part I'm having issues with)
$owner = $user.'Network User ID'}
$loginID = $user.'Network User ID'
$Identity = Get-ADUser -Identity $owner -Properties Displayname |Select-Object -ExpandProperty Displayname
$manager = $user.'Provide Inbox Access To'
$NewOwner = $user.'Provide users email group ownership to'
$NewOwnerID = $User.'Provide users email group ownership To'
What I need it to do is throw an error if ANY entry in the CSV is blank, and terminate. The most promising idea that I tried was:
If ($Owner -eq $Null)
{
Write-Host "Invalid entry, the Network User ID field cannot be blank"
Write-Host "Press Enter to Exit..."
Exit
}
Else
{
#Do everything else
}
But even that still fails.
In summary, what I need to do is throw a custom terminating error if an entry in the CSV is blank.
Any help is greatly appreciated!
EDIT
If this helps, here is more of the real code...
$Confirmation = Read-Host "Please double check the information in the file. Are you sure you want to continue? (Y/N)"
If($Confirmation -eq "Y")
{
Write-Host "You have chosen to proceed. Processing Termination" -BackgroundColor DarkCyan
#Import file
$file = "C:\TerminateUsers.csv"
$data = Import-Csv $file
#Set disabled OU
$disabledOU = "OU=Users,OU=Disabled Accounts, OU=Corporate"
$colOutput = #()
foreach ($user in $data)
{
#Grab variables from CSV
$owner = $user.'Terminated Network User ID'}
$loginID = $user.'Terminated Network User ID'
#Displayname required for Outlook functions
$Identity = Get-ADUser -Identity $owner -Properties Displayname |Select-Object -ExpandProperty Displayname
$manager = $user.'Provide Inbox Access To'
$NewOwner = $user.'Provide users email group ownership to'
$NewOwnerID = $User.'Provide users email group ownership To'
If (Get-ADUser -LDAPFilter "(sAMAccountName=$loginID)")
{
$date = Get-Date -Format d
#Disable account, change description, disable dialin, remove group memberships
Set-ADUser -Identity $loginID -Enabled $false
Set-ADUser -Identity $loginID -Replace #{Description = "Terminated $date"}
Set-ADUser -Identity $loginID -Replace #{msNPAllowDialin = $False}
RemoveMemberships $loginID
This isn't all of it, but this is the part we're working with...
There's a number of issues you're going to run into here.
First, $Owner -eq $Null isn't going to do what you likely want to do. Mainly, the issue is that an empty string is not a null value. They're different. Instead, your test should be:
if ([string]::IsNullOrEmpty($owner)) { ... }
Or:
if ([string]::IsNullOrWhiteSpace($owner)) { ... }
This second one returns true if the string includes only tabs, spaces, or other whitespace characters, or is an empty string, or is null.
Second, to throw an exception, you need to use the throw keyword. See Get-Help about_Throw. For example:
if ([string]::IsNullOrWhiteSpace($owner)) {
throw "Owner is null or empty.";
}
If you have this embedded in a try block, you can catch the exception with the associated catch blocks. See Get-Help about_Try_Catch_Finally. You can also use Trap, I believe (See Get-Help about_Trap).
Finally, the default action when an error is encountered is controlled by the $ErrorActionPreference variable. That variable's default value is Continue, so error messages will be displayed but the script will continue executing as though no error happened at all. I'm not entirely sure how this works with manually thrown exceptions and try/catch blocks, but unless I know that I want my script to ignore errors, I start just about every script with:
$ErrorActionPreference = Stop;
See Get-Help about_Preference_Variables and Get-Help about_CommonParameters for more about this one.
Consider the following dataset. Note the null for Last_Name for one of the columns.
user_name first_name last_name
--------- ---------- ---------
lrivera0 Lawrence Rivera
tlawrence1 Theresa Lawrence
rboyd2 Roy
cperry3 Christine Perry
jmartin4 Jessica Martin
So if we want to be sure to only process full rows then a simple If would cover that.
Import-Csv .\text.csv | ForEach-Object{
If($_.Psobject.Properties.Value -contains ""){
# There is a null here somewhere
Throw "Null encountered. Stopping"
} else {
# process as normal
}
}
Problem is that Import-CSV treats nulls as zero length strings. I tried using -contains on just $_ but it did not work as $_ is not an array but an object with properties. So I used the object properties value to perform the comparison against.
Bacon brought up an interesting point in that this code would not account for whitespace only empty values.
We use throw so processing stops if a null is encountered. Using that if block you can do whatever action you want.

Powershell Call Specific CSV Based On HostName

hoping someone can help out as im banging my head against the wall a little here ...
I have a simple CSV file, 2 columns, 1 for HostName and 1 for Password.
For example;
HostName,Password
Computer1,Password1
Computer2,Password2
etc
What I need to do is read the password from the CSV, based on the HostName of the device the script is running on.
This is for BitLocker PIN encryption and so instead of me specifying the PIN in my current PowerShell script, it would read the value from the CSV and encrypt using that.
Cheers guys,
In a very general way, you can grab your object (CSV) file and filter with where-object. Once that is stuffed into a variable, you can just call the property with a "."
$Comp1 = Get-MyCSV | Where {$_.HostName -eq Computer1}
$Comp1.Password
Resolved now thanks for the input chaps.
$InSecureString = Import-Csv "C:\EncryptionPasswords.csv"
$BitLockerPassword = $InSecureString.Where({$PSItem.ComputerName -eq $env:COMPUTERNAME}).Password
$BitLockerPassword
Then called the $BitLockerPassword variable and converted to SecureString.
An alternative to using Where-Object every time you need to retrieve a password based on hostname, would be to create a hashtable from the values:
$LookupTable = #{}
Import-Csv .\passwords.csv |ForEach-Object {
$LookupTable[$_.HostName] = ConvertTo-SecureString $_.Password -AsPlainText -Force
}
Now you can retrieve the corresponding password as a secure string directly from the hashtable:
$MachineName = $env:ComputerName
Enable-BitLocker -MountPoint "C:" -Pin $LookupTable[$MachineName] -TPMandPinProtector

Powershell: Reading in a column from a .CSV file and then adding a specific string to the beginning and exporting again

I'm attempting to write a script which will read in a CSV generated by querying AD for user information (that part is done) but then will allow me to add a string to the beginning of each value of a column in the CSV file and then export it.
For instance we have this CSV file:
"displayname","Office"
Bob,7142
Janet,8923
SantaClaus,0912
NicCage,0823
I want to take each entry for "Office", add the string "BUG" before it and then export it back out. The modified CSV should look like:
"displayname","Office"
Bob,BUG7142
Janet,BUG8923
SantaClaus,BUG0912
NicCage,BUG0823
At this point, I've been attempting to read in just the "Office" column and then displaying it with "Write-Host". The idea being that if I can do that then maybe I can create a new variable that would be something like:
$BUG = "BUG"
$NewVar = $BUG$Office
Which would hopefully look like the second CSV file. I am extremely new to powershell scripting.
The attempts I've made so far are these:
Attempt #1:
$UserList = Import-CSV C:\Users\username\CSV.csv
$UserList | ForEach-Object ($_.Office) { $UserList }
Attempt #2:
$projectName = import-csv C:\Users\username\CSV.csv | % {$_.Office}
$BUG = "BUG"
$projectName | ForEach-Object ($_) {$projectName}
Attempt #3:
$UserList = Import-CSV C:\Users\username\CSV.csv
#ForEach ($Office in $Userlist) {
#Write-Host $UserList.Office
#}
Attempt #4:
Import-Csv "C:\Users\username\CSV.csv" -Header ("displayname","Office","whenCreated","EmailAddress") | Select-Object Office | Export-CSV -Path C:\users\Username\test.csv
I have gotten it to read out just the Office numbers before using the ForEach-Object loop structure but then it never stops reading out the office numbers so that's unhelpful.
I think I'm going in the right direction, but I just can't figure out how to modify a column like this.
Instead of trying to extract the Office column, just pipe the full data set (all columns) to ForEach-Object, change the value of the Office property and pipe it back to Export-Csv:
$Prefix = "BUG"
Import-Csv .\file.csv | ForEach-Object {
$_.Office = $Prefix + $_.Office
$_
} | Export-Csv .\file_modified.csv -NoTypeInformation