PowerShell Custom Columns Grid View - powershell

I'm sure i've done something wrong, but i'm playing around with accessing multiple office 365 powershells and it works fine, but I want to add custom columns in my grid view. 1 column saying "Client Name" another saying something else. This is what I've got so far.
# Prompt For Login
[void][Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')
$title = 'Email Address'
$msg = 'Enter your email address:'
$emailAddress = [Microsoft.VisualBasic.Interaction]::InputBox($msg, $title)
# Connect Office 365
if (Get-Module -ListAvailable -Name ExchangeOnlineManagement) {
Write-Host "Module Exists"
} else {
Write-Host "Module Does not Exist, Installing..."
Install-Module ExchangeonlineManagement
}
$clients = #("ClientA",
"ClientB",
"ClientC",
"ClientD",
"ClientE")
$client = $clients | Out-GridView -Title "Choose a Client" -Passthru
# Make The Connection
Connect-ExchangeOnline -UserPrincipalName $emailAddress -ShowProgress $true -DelegatedOrganization $client

The key is to send objects to Out-GridView.
This should help you get where you want:
$clients = [PSCustomObject] #{Client="ClientA";OtherData='Something'},
[PSCustomObject] #{Client="ClientB";OtherData='You'},
[PSCustomObject] #{Client="ClientC";OtherData='Want'},
[PSCustomObject] #{Client="ClientD";OtherData='To'},
[PSCustomObject] #{Client="ClientE";OtherData='Show'}
$choice= $clients | Out-GridView -Title "Choose a Client" -Passthru
#the output from Out-Gridview is now an object, so use dot-notation to get the client.
Connect-ExchangeOnline -UserPrincipalName $emailAddress -ShowProgress $true -DelegatedOrganization $choice.Client

Related

Powershell - combining multiple for each into a single output

Good morning everyone,
I am still learning powershell and have a script that my company run's. I have adjusted it slightly and it works well. however...
Overview
Script pulls in a CSV file and then for each device on the CSV it logs in and grabs all of the VIP information and then outputs it to a CSV that is dated and titled with the device name.
Ask
I would like adjust the script so that instead of having 50+ CSV files I could have a single CSV file with an extra column that would like the device name that all the VIPS are on. How do I do that?
Current Script
$user = "user"
$pass1 = Read-Host "Enter Netscaler Password"
$Devicelist = Import-Csv'C:\Users\user\Documents\20221110\20221109_Citrix_inventory_Master1.csv'
foreach ($device in ($Devicelist | ? { $_.fqdn -match "nsr" -and $_.State -match "Primary" -and $_.Configuration_viewable_with_Techops_login -match "Yes" })) {
Write-Host "Attempting to connect to $($device.fqdn)"
$SecurePassword = ConvertTo-SecureString $pass1 -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential ($user, $SecurePassword)
$session = Connect-NetScaler -Hostname $device."IP address" -Credential $Credential -PassThru
$nsVIPs = Get-NSLBVirtualServer | select name, ipv46, port, curstate
$nsVIPs | Out-File C:\Users\user\Documents\20221110\VIPS\$(get-date -f yyyyMMdd)"_"$($device.fqdn)-"vips.csv"
}
Current CSV Input File format
Current output file format
What I would like to out file format to be
**
What have I tried
**
At the moment nothing except for research, I am guessing that I will need to hold of of the info in an array and then output it at the end. I just don't have a clue how to do that.
Thanks for looking and helping
Neil
You can change the code to first collect all data in one single variable $result and after the loop write all that out in a single CSV file.
To write csv, you need to use Export-Csv, not Out-File, which is intended to write simple text, not objects.
$user = "user"
$pass1 = Read-Host "Enter Netscaler Password"
$SecurePassword = ConvertTo-SecureString $pass1 -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential ($user, $SecurePassword)
$today = '{0:yyyyMMdd}' -f (Get-Date)
$Devicelist = Import-Csv -Path 'C:\Users\user\Documents\20221110\20221109_Citrix_inventory_Master1.csv' |
Where-Object { $_.fqdn -match "nsr" -and
$_.State -match "Primary" -and
$_.Configuration_viewable_with_Techops_login -match "Yes" }
$result = foreach ($device in $Devicelist) {
Write-Host "Attempting to connect to $($device.fqdn)"
$session = Connect-NetScaler -Hostname $device.'IP address' -Credential $Credential -PassThru
Get-NSLBVirtualServer |
Select-Object name, ipv46, port, curstate, #{Name = 'Device Name'; Expression = {$device.fqdn}}
}
# now write out the csv file just once
$result | Export-Csv -Path "C:\Users\user\Documents\20221110\VIPS\$($today)_vips.csv" -NoTypeInformation

Invoke-VMScript: Do not confirm/re-enter guest credentials

I'm performing an audit on VMs in our environment, and using Invoke-VMScript to get disk info:
$vmErrors = New-Object System.Collections.Generic.List[System.Object]
$report = foreach ($VM in $VMs){
$name = $vm.Name
Write-Host "Retrieving data for $name... " -NoNewline
try{
$output = Invoke-VMScript -ScriptText #'
Get-Disk | Foreach-Object{
[PSCustomObject]#{
ComputerName = $env:COMPUTERNAME
Number = $_.number
Size = [int]($_.size/1GB)
PartitionStyle = $_.PartitionStyle
}
} | ConvertTo-Csv -NoTypeInformation
'# -VM $name -GuestUser $Username -GuestPassword $Password -WarningAction SilentlyContinue -ErrorAction Stop
if($output.ScriptOutput -match 'PartitionStyle')
{
$output.ScriptOutput -replace '(?s)^.+(?="Com)' | ConvertFrom-Csv
}
Write-Host "Done" -ForegroundColor Green
}catch{
$vmErrors.Add($name)
Write-Host "Error!" -ForegroundColor Red
}
}
When running the code in Powershell ISE, I do not need to confirm the credentials for each VM and the script loops perfectly fine, however if I run the script in a standard Powershell window, for each VM I have to enter the username and password for each VM (the credentials will always be the same as what I use to authenticate with the vCenter server.
Example:
Retrieving data for VM NAME...
Specify Credential
Please specify guest credential
User:
How can I run this in a normal window and avoid having to re-enter my credentials each time?
Edit
Example of setting username & password:
$Username = ""
$Password = ""
Function GetUser{
do{
$global:Username = Read-Host "What is your username? (DOMAIN\Username)"
}while($global:Username -eq "")
}
Function GetPassword{
do{
$global:Password = Read-Host "What is your password?" -AsSecureString
$global:Password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($global:Password))
}while($global:Password -eq "")
}
Solved by changing the credential references in Invoke-VMScript to use $global:Username and $global:Password

Export 365 Users Mailboxes Size and Unit in separate columns

I have good script that export 365 Users Mailboxes Size to csv file.
The results looks like that:
Today it display the Total Size with the Unit (KB/MB/GB) inside the same column.
As for the Total Size (Bytes)- i dont really need that column.
So, i want to separate the Total Size column into 2 separate columns of Size and Unit columns.
Like that:
So at the end, the results will be:
Here's the code:
Param(
[Parameter(Mandatory = $false)]
[switch]$MFA,
[switch]$SharedMBOnly,
[switch]$UserMBOnly,
[string]$MBNamesFile,
[string]$UserName,
[string]$Password
)
Function Get_MailboxSize{
$Stats=Get-MailboxStatistics -Identity $UPN
$IsArchieved=$Stats.IsArchiveMailbox
$ItemCount=$Stats.ItemCount
$TotalItemSize=$Stats.TotalItemSize
$TotalItemSizeinBytes= $TotalItemSize –replace “(.*\()|,| [a-z]*\)”, “”
$TotalSize=$stats.TotalItemSize.value -replace "\(.*",""
$DeletedItemCount=$Stats.DeletedItemCount
$TotalDeletedItemSize=$Stats.TotalDeletedItemSize
#Export result to csv
$Result=#{'Display Name'=$DisplayName;'User Principal Name'=$upn;'Mailbox Type'=$MailboxType;'Primary SMTP Address'=$PrimarySMTPAddress;'IsArchieved'=$IsArchieved;'Item Count'=$ItemCount;'Total Size'=$TotalSize;'Total Size (Bytes)'=$TotalItemSizeinBytes;'Deleted Item Count'=$DeletedItemCount;'Deleted Item Size'=$TotalDeletedItemSize;'Issue Warning Quota'=$IssueWarningQuota;'Prohibit Send Quota'=$ProhibitSendQuota;'Prohibit send Receive Quota'=$ProhibitSendReceiveQuota}
$Results= New-Object PSObject -Property $Result
$Results | Select-Object 'Display Name','User Principal Name','Mailbox Type','Primary SMTP Address','Item Count','Total Size','Total Size (Bytes)','IsArchieved','Deleted Item Count','Deleted Item Size','Issue Warning Quota','Prohibit Send Quota','Prohibit Send Receive Quota' | Export-Csv -Path $ExportCSV -Notype -Append
}
Function main(){
#Check for EXO v2 module inatallation
$Module = Get-Module ExchangeOnlineManagement -ListAvailable
if($Module.count -eq 0){
Write-Host Exchange Online PowerShell V2 module is not available -ForegroundColor yellow
$Confirm= Read-Host Are you sure you want to install module? [Y] Yes [N] No
if($Confirm -match "[yY]") {
Write-host "Installing Exchange Online PowerShell module"
Install-Module ExchangeOnlineManagement -Repository PSGallery -AllowClobber -Force
}
else {
Write-Host EXO V2 module is required to connect Exchange Online.Please install module using Install-Module ExchangeOnlineManagement cmdlet.
Exit
}
}
#Connect Exchange Online with MFA
if($MFA.IsPresent){
Connect-ExchangeOnline
}
#Authentication using non-MFA
else{
#Storing credential in script for scheduling purpose/ Passing credential as parameter
if(($UserName -ne "") -and ($Password -ne "")){
$SecuredPassword = ConvertTo-SecureString -AsPlainText $Password -Force
$Credential = New-Object System.Management.Automation.PSCredential $UserName,$SecuredPassword
}
else{
$Credential=Get-Credential -Credential $null
}
Connect-ExchangeOnline -Credential $Credential
}
#Output file declaration
$ExportCSV=".\MailboxSizeReport_$((Get-Date -format yyyy-MMM-dd-ddd` hh-mm` tt).ToString()).csv"
$Result=""
$Results=#()
$MBCount=0
$PrintedMBCount=0
Write-Host Generating mailbox size report...
#Check for input file
if([string]$MBNamesFile -ne "") {
#We have an input file, read it into memory
$Mailboxes=#()
$Mailboxes=Import-Csv -Header "MBIdentity" $MBNamesFile
foreach($item in $Mailboxes){
$MBDetails=Get-Mailbox -Identity $item.MBIdentity
$UPN=$MBDetails.UserPrincipalName
$MailboxType=$MBDetails.RecipientTypeDetails
$DisplayName=$MBDetails.DisplayName
$PrimarySMTPAddress=$MBDetails.PrimarySMTPAddress
$IssueWarningQuota=$MBDetails.IssueWarningQuota -replace "\(.*",""
$ProhibitSendQuota=$MBDetails.ProhibitSendQuota -replace "\(.*",""
$ProhibitSendReceiveQuota=$MBDetails.ProhibitSendReceiveQuota -replace "\(.*",""
$MBCount++
Write-Progress -Activity "`n Processed mailbox count: $MBCount "`n" Currently Processing: $DisplayName"
Get_MailboxSize
$PrintedMBCount++
}
}
#Get all mailboxes from Office 365
else{
Get-Mailbox -ResultSize Unlimited | foreach {
$UPN=$_.UserPrincipalName
$Mailboxtype=$_.RecipientTypeDetails
$DisplayName=$_.DisplayName
$PrimarySMTPAddress=$_.PrimarySMTPAddress
$IssueWarningQuota=$_.IssueWarningQuota -replace "\(.*",""
$ProhibitSendQuota=$_.ProhibitSendQuota -replace "\(.*",""
$ProhibitSendReceiveQuota=$_.ProhibitSendReceiveQuota -replace "\(.*",""
$MBCount++
Write-Progress -Activity "`n Processed mailbox count: $MBCount "`n" Currently Processing: $DisplayName"
if($SharedMBOnly.IsPresent -and ($Mailboxtype -ne "SharedMailbox")){
return
}
if($UserMBOnly.IsPresent -and ($MailboxType -ne "UserMailbox")){
return
}
Get_MailboxSize
$PrintedMBCount++
}
}
#Open output file after execution
If($PrintedMBCount -eq 0){
Write-Host No mailbox found
}
else{
Write-Host `nThe output file contains $PrintedMBCount mailboxes.
if((Test-Path -Path $ExportCSV) -eq "True"){
Write-Host `nThe Output file available in $ExportCSV -ForegroundColor Green
$Prompt = New-Object -ComObject wscript.shell
$UserInput = $Prompt.popup("Do you want to open output file?",0,"Open Output File",4)
If ($UserInput -eq 6){
Invoke-Item "$ExportCSV"
}
}
}
#Disconnect Exchange Online session
Disconnect-ExchangeOnline -Confirm:$false | Out-Null
}
. main
Replace line:
$Results | Select-Object 'Display Name','User Principal Name','Mailbox Type','Primary SMTP Address','Item Count','Total Size','Total Size (Bytes)','IsArchieved','Deleted Item Count','Deleted Item Size','Issue Warning Quota','Prohibit Send Quota','Prohibit Send Receive Quota' | Export-Csv -Path $ExportCSV -Notype -Append
With:
$Results | Select-Object 'Display Name','User Principal Name','Mailbox Type','Primary SMTP Address','Item Count',#{Name = 'Total Size'; Expression = {($_."Total Size").Split(" ")[0]}},#{Name = 'Unit'; Expression = {($_."Total Size").Split(" ")[1]}},'Total Size (Bytes)','IsArchieved','Deleted Item Count','Deleted Item Size','Issue Warning Quota','Prohibit Send Quota','Prohibit Send Receive Quota' | Export-Csv -Path $ExportCSV -Notype -Append
I have replaced 'total size' with the 2 following calculated properties:
#{Name = 'Total Size'; Expression = {($_."Total Size").Split(" ")[0]}}
#{Name = 'Unit'; Expression = {($_."Total Size").Split(" ")[1]}}
This splits the value into an array and will put them into the specified properties of "Total Size" & "Unit"
You can use -csplit (case-sensitive -split) to split the TotalItemSize value by the unit. This will create an array of three items. The third item will be the (# bytes) value that you are replacing anyway.
$Stats=Get-MailboxStatistics -Identity $UPN
$TotalItemSize,$Unit = $Stats.TotalItemSize.Value -csplit '(\b[A-Z]+\b)').Trim()[0,1]
$Unit will now have the unit and $TotalItemSize will contain the size without the unit. Trim() is to remove surrounding spaces from the formatting.
You could technically do all of your size manipulations with one line:
$TotalItemSize,$Unit,$TotalSizeInBytes = ($Stats.TotalItemSize.Value -split ' ' -replace '\(|,')[0,1,2]

How to create Teams with Powershell with a CSV file

I have to manually create Teams, so i thought i would be a good idea to make this proces automatic. The code keeps giving me the error "Cannot validate argument on parameter "DisplayName. The argument is Null or empty".
It is for Windows Server 2012 R2, I think it does recognize the csv file because this is the only error that i'm getting
This is my CSV file
$datacsv = import-csv C:\Users\$$$$$\Desktop\test.csv
Import-Module MicrosoftTeams
foreach ($data in $datacsv)
{
$cred = Get-Credential
Connect-MicrosoftTeams -Credential $cred
$teamname = $data.TeamsName
$owner = $data.Owners
$accestype = $data.TeamType
$member = $data.Members
$group = New-team -DisplayName $teamname -Owner $owner -AccesType $accestype
Add-TeamUser -User $member -GroupId $group.GroupId -DisplayName $teamname
Add-Teamuser -User $owner -GroupId $group.GroupId -DisplayName $owner
}
I expected that the teams would indeed create but this didnt happen.
Sorry for the bad English, my writing is pretty bad.

Powershell Script to Disable Inactive AD Users Create Log and Send E-mail

A colleague has reached out to me to create a PowerShell script to do the following:
The script would read the lastlogondate of an AD security group called “Temp Associates”, disable the accounts with lastlogondate > or = 29 days from current date and move to Disabled OU. When it disables it will also change the descripton to the date it was disabled on. Then create a report listing disabled users and email to our global helpdesk.
I've compiled some things together that seem like they should work, but do not. When I run the script I receive no error message and the log file is generated with no data populated. In order to remain SOX compliant I should be able to manipultate the value in $PasswordAge = (Get-Date).adddays(-29) for testing purposes as I'm not sure we have any accounts that meet the requirements currently.
E-mail is working now, just had to create PSCredential to use in send-mailmessage -credential parameter.
I am definitley new to PowerShell and can use all the help I can get. Any suggestions to either improve the existing code or use a different method are welcome, but I'd like to utilize what I already have if possible.
Code Below:
#import the ActiveDirectory Module
Import-Module ActiveDirectory
#Create a variable for the date stamp in the log file
$LogDate = get-date -f yyyyMMddhhmm
#Sets the OU to do the base search for all user accounts, change for your env.
$SearchBase = "CN=Temp Associates,OU=Res Accounts,DC=our,DC=domain,DC=org"
#Create an empty array for the log file
$LogArray = #()
#Sets the number of days to disable user accounts based on lastlogontimestamp and pwdlastset.
$PasswordAge = (Get-Date).adddays(-29)
#Use ForEach to loop through all users with pwdlastset and lastlogontimestamp greater than date set. Also added users with no lastlogon date set. Disables the accounts and adds to log array.
#Add the properties you will be using to ensure they are available.
$DisabledUsers = (Get-ADUser -searchbase $SearchBase -Properties samaccountname, name, distinguishedname -filter {((lastlogondate -notlike "*") -OR (lastlogondate -le $Passwordage)) -AND (enabled -eq $True) -AND (whencreated -le $Passwordage)} )
if ($DisabledUsers -ne $null -and $DisabledUsers.Count > 0) {
ForEach ($DisabledUser in $DisabledUsers) {
#Sets the user objects description attribute to a date stamp. Example "11/13/2011"
set-aduser $DisabledUser -Description ((get-date).toshortdatestring()) -whatif
#Disabled user object. To log only add "-whatif"
Disable-ADAccount $DisabledUser -whatif
#Create new object for logging
$obj = New-Object PSObject
$obj | Add-Member -MemberType NoteProperty -Name "Name" -Value $DisabledUser.name
$obj | Add-Member -MemberType NoteProperty -Name "samAccountName" -Value $DisabledUser.samaccountname
$obj | Add-Member -MemberType NoteProperty -Name "DistinguishedName" -Value $DisabledUser.DistinguishedName
$obj | Add-Member -MemberType NoteProperty -Name "Status" -Value 'Disabled'
#Adds object to the log array
$LogArray += $obj
}
# Move disabled users in Temp Associates group to Disabled OU
Search-ADAccount –AccountDisabled –UsersOnly –SearchBase “CN=Temp Associates,OU=Res Accounts,DC=our,DC=domain,DC=org” |
Move-ADObject –TargetPath “OU=Disabled,DC=our,DC=domain,DC=org” -WhatIf
#Exports log array to CSV file in the temp directory with a date and time stamp in the file name.
$logArray | Export-Csv "C:\Temp\User_Report_$logDate.csv" -NoTypeInformation
#Create PSCredential for use in e-mail -credential parameter
$secpasswd = ConvertTo-SecureString "PasswordHere" -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential ("UserHere", $secpasswd)
#Send e-mail to Global Helpdesk with report generated
$emailFrom = "smtp#address.com"
$emailTo = "User#address.com"
$subject = "NA Disabled Temp Users to be deleted"
$smtpServer = "smtp.address.com"
$attachment = "C:\Temp\User_Report_$logDate.csv"
Send-MailMessage -To $emailTo -From $emailFrom -Subject $subject -SmtpServer $smtpServer -attachment $attachment -credential $mycreds
}else {
Write-Output "No disabled users to process for $PasswordAge."
#Create PSCredential for use in e-mail -credential parameter
$secpasswd = ConvertTo-SecureString "PasswordHere" -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential ("UserHere", $secpasswd)
#Send e-mail to Global Helpdesk with report generated
$emailFrom = "smtp#address.com"
$emailTo = "User#address.com"
$subject = "NA Disabled Temp Users to be deleted"
$smtpServer = "smtp.address.com"
$attachment = "C:\Temp\User_Report_$logDate.csv"
Send-MailMessage -To $emailTo -From $emailFrom -Subject $subject -Body "No disabled users to process for $PasswordAge." -SmtpServer $smtpServer -credential $mycreds
}
Putting it as an answer, even though it is not a direct answer.
It is really hard to say what is wrong especially when you are not implementing any checks along the way. A basic debugging strategy would be to add a few outputs along the way to see if the script is hitting sections. Such was: write-output "Entering Foreach" and write-output "Looping user $($DisabledUser.samaccountname)" to ensure that your script is executing properly. This will help determine where your hiccup is.
Alternatively, where I would first look is in your Get-ADUser query. Run that alone and make sure it returns users. If not get it to where it returns expected results.
Here is a revised version of your code that has an error check if there are no users returned.
#import the ActiveDirectory Module
Import-Module ActiveDirectory
#Create a variable for the date stamp in the log file
$LogDate = get-date -f yyyyMMddhhmm
#Sets the OU to do the base search for all user accounts, change for your env.
$SearchBase = "CN=Temp Associates,OU=Res Accounts,DC=our,DC=domain,DC=org"
#Create an empty array for the log file
$LogArray = #()
#Sets the number of days to disable user accounts based on lastlogontimestamp and pwdlastset.
$PasswordAge = (Get-Date).adddays(-29)
#Use ForEach to loop through all users with pwdlastset and lastlogontimestamp greater than date set. Also added users with no lastlogon date set. Disables the accounts and adds to log array.
#Add the properties you will be using to ensure they are available.
$DisabledUsers = (Get-ADUser -searchbase $SearchBase -Properties samaccountname, name, distinguishedname -filter {((lastlogondate -notlike "*") -OR (lastlogondate -le $Passwordage)) -AND (enabled -eq $True) -AND (whencreated -le $Passwordage)} )
if ($DisabledUsers -ne $null -and $DisabledUsers.Count > 0) {
ForEach ($DisabledUser in $DisabledUsers) {
#Sets the user objects description attribute to a date stamp. Example "11/13/2011"
set-aduser $DisabledUser -Description ((get-date).toshortdatestring()) -whatif
#Disabled user object. To log only add "-whatif"
Disable-ADAccount $DisabledUser -whatif
#Create new object for logging
$obj = New-Object PSObject
$obj | Add-Member -MemberType NoteProperty -Name "Name" -Value $DisabledUser.name
$obj | Add-Member -MemberType NoteProperty -Name "samAccountName" -Value $DisabledUser.samaccountname
$obj | Add-Member -MemberType NoteProperty -Name "DistinguishedName" -Value $DisabledUser.DistinguishedName
$obj | Add-Member -MemberType NoteProperty -Name "Status" -Value 'Disabled'
#Adds object to the log array
$LogArray += $obj
}
# Move disabled users in Temp Associates group to Disabled OU
Search-ADAccount –AccountDisabled –UsersOnly –SearchBase “CN=Temp Associates,OU=Res Accounts,DC=our,DC=domain,DC=org” |
Move-ADObject –TargetPath “OU=Disabled,DC=our,DC=domain,DC=org” -WhatIf
#Exports log array to CSV file in the temp directory with a date and time stamp in the file name.
$logArray | Export-Csv "C:\Temp\User_Report_$logDate.csv" -NoTypeInformation
#Send e-mail to Global Helpdesk with report generated
$emailFrom = "sender#mail.com"
$emailTo = "recipient#mail.com"
$subject = "NA Disabled Temp Users to be deleted"
$smtpServer = "smtp.server.com"
$attachment = "C:\Temp\User_Report_$logDate.csv"
Send-MailMessage -To $emailTo -From $emailFrom -Subject $subject -SmtpServer $smtpServer -attachment $attachment
}else {
Write-Output "No disabled users to process for $PasswordAge."
}
i found that the code in the if is never executed.
You must replace $DisabledUsers.Count > 0 with $DisabledUsers.Count -gt 0