Powershell Get-mailboxdatabase and Create Shared Mailbox Script - database

I have some basic Powershell knowledge and i am trying to revise an existing script on our Service Desk to make a shared mailbox in Exchange 2010.
The current version was setup so the user can input the database to assign the mailbox to.
The revised version i am trying to do is suppose to pull the Databases and display the size of each database. Then the idea is the user can simply input a number value to represent a database, rather than writing out the whole database.
So after doing some research i tried out the following;
$mailboxname=Read-Host “Enter mailbox name”
$alias=Read-Host “Enter Email Alias”
$User=$alias + "#domain.com"
Get-MailboxDatabase -Server "Server" -Status | Where-Object {$_.name -like "Database*"} | Sort-Object -Descending -Property #{Expression = "name"; Descending = $true} | Select Name,Databasesize
$script:ChosenDatabase=Get-MailboxDatabase
function Get-MailboxDatabase
{
$database=Read-Host "Enter database using a value of 1 to 4 to add the mailbox to"
Switch ($database)
{
1 {$Chosendatabase="Database-1"}
2 {$Chosendatabase="Database-2"}
3 {$Chosendatabase="Database-3"}
4 {$Chosendatabase="Database-4"}
}
return $Chosendatabase
}
New-mailbox -shared -Name $mailboxname -alias $alias -UserPrincipalName $User -OrganizationalUnit "Domain.com/Resources-OU" -Database $Chosendatabase
Get-mailbox -Identity $User | ft DisplayName,Database
read-host "hit enter to close window"
This kinda works, but it doesn't show the Mailbox Database and as can be seen in the example below it did a double up of the readhost to enter the database
Enter mailbox name: testscript2
Enter Email Alias: testscript2
Enter database using a value of 1 to 4 to add the mailbox to: 2
Enter database using a value of 1 to 4 to add the mailbox to: 2
Name Alias ServerName ProhibitSendQuota
---- ----- ---------- -----------------
testscript2 testscript2 Server unlimited
DisplayName Database
----------- --------
testscript2 Database-2
hit enter to close window:
So i found Show output before Read-Host, which i tried out to see if this will help show the mailboxdatabase before inputting a value.
Changed;
Get-MailboxDatabase -Server "Server" -Status | Where-Object {$_.name -like "Database*"} | Sort-Object -Descending -Property #{Expression = "name"; Descending = $true} | Select Name,Databasesize
To;
$getDB=Get-MailboxDatabase -Server "Server" -Status | Where-Object {$_.name -like "Database*"} | Sort-Object -Descending -Property #{Expression = "name"; Descending = $true} | Select Name,Databasesize | Out-String;
Write-Host $getDB
But got the following errors
Enter mailbox name: testScript
Enter Email Alias: testscript
Name DatabaseSize
---- ------------
Database-4 762.8 GB
Database-3 376.3 GB
Database-2 249.3 GB
Database-1 829.8 GB
Cannot process argument transformation on parameter 'Database'. Cannot convert the
"System.Collections.ArrayList" value of type
"System.Collections.ArrayList" to type "Microsoft.Exchange.Configuration.Tasks.DatabaseIdParameter".
+ CategoryInfo : InvalidData: (:) [New-Mailbox], ParameterBindin...mationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,New-Mailbox
+ PSComputerName : Domain.com
The operation couldn't be performed because object 'testscript#domain.com' couldn't be found on
'Domain.com'.
+ CategoryInfo : NotSpecified: (:) [Get-Mailbox], ManagementObjectNotFoundException
+ FullyQualifiedErrorId : 8D2D2EF6,Microsoft.Exchange.Management.RecipientTasks.GetMailbox
+ PSComputerName : Domain.com
hit enter to close window:
Is anybody able to help shed some light on what i am doing wrong and why I am getting a double of the read-host.

Figured this problem out awhile ago and thought to post the solution here.
My mistake was the function was incorrect and shouldn't of been named
function Get-MailboxDatabase
This caused the issue as i was creating a function using an existing cmdlet name (DERP)
I changed my script to the following
$data = Get-MailboxDatabase -Server "Server" -Status | Where-Object {$_.name -like "DATABASE*"} | Sort-Object -Property #{Expression = "name"} | Select Name,Databasesize | ft | Out-String
function WORK
{
Write-host $data
Write-host "Pick the database with the lowest size"
Write-host
$database=Read-Host "Enter the database using a value of 1 to 4 to add the mailbox to"
Switch ($database)
{
1 {$Chosendatabase="DATABASE-1"}
2 {$Chosendatabase="DATABASE-2"}
3 {$Chosendatabase="DATABASE-3"}
4 {$Chosendatabase="DATABASE-4"}
}
return $Chosendatabase
}
$date=Get-Date -format d
$mailboxname=Read-Host “Enter the mailbox name”
$alias=Read-Host “Enter Email Alias”
$User=$alias + "#domain.com"
$ticket=Read-Host "Enter the Ticket number"
$notes="Mailbox created - $ticket - $date"
Read-Host "hit enter to Continue"
$script:ChosenDatabase = WORK
New-mailbox -shared -Name $mailboxname -alias $alias -UserPrincipalName $User -OrganizationalUnit "domain.com/Resources-OU" -Database $Chosendatabase
Set-user -identity $alias -notes "$Notes"
##This command is to make sure a copy of sent emails are stored on the shared mailbox as well as the senders mailbox
Set-MailboxSentItemsConfiguration -Identity $alias -SendAsItemsCopiedTo SenderAndFrom -SendOnBehalfOfItemsCopiedTo SenderAndFrom
##bring back confirmation the script has done as tended
Get-mailbox -Identity $User | ft DisplayName,Database
Get-mailboxsentitemsconfiguration -Identity $alias
read-host "hit enter to close window"
This has been working fine for us for the past few months

Related

Powershell Format Arrays to two dimensional Arrays

i had a problem a few days ago where my script that is supposed to extract all hostnames from an AD OU and then check for the space used and free space on disks for every single host. Since this is the first time i do something with powershell i ran into many problems. The Problem that i got now is that the script cant find the hostnames listed in an array. I think i found out why it wont work because it uses the wrong hostname.
Error message i get for every hostname:
Write-Warning : Es wurde kein Positionsparameter gefunden, der das Argument "#{Name=BUCHHOLZMVZ}" akzeptiert.
In Zeile:16 Zeichen:5
+ Write-Warning "Server " $server "nicht erreichbar"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Write-Warning], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.WriteWarningCommand
When i only use the command to get all hostnames of all servers i get:
Name
----
someserver
someserver1
someserver2
(and so on...)
Here is the script:
$servers = Get-ADComputer -Filter * -SearchBase "OU=ServerOU, DC=somedomain, DC=somedomain, DC=somedomain" | Select-Object Name
$allDisks = foreach ($server in $servers)
{
try {
Get-WmiObject Win32_LogicalDisk -ComputerName $server -Filter DriveType=3 -ErrorAction Stop |
Select-Object #{'Name'='ComputerName'; 'Expression'={$server}},
DeviceID,
#{'Name'='Size'; 'Expression'={[math]::truncate($_.size / 1GB)}},
#{'Name'='Freespace'; 'Expression'={[math]::truncate($_.freespace / 1GB)}}
}
catch {
Write-Warning "Server " $server "nicht erreichbar"
Continue
}
}
$allDisks |Export-Csv C:\Servers.csv -NoTypeInformation
Use the following for your first line:
$servers = Get-ADComputer -Filter * -SearchBase "OU=ServerOU, DC=somedomain, DC=somedomain, DC=somedomain" |
Select-Object -Expand Name
Using Select-Object without -Expand or -ExpandProperty outputs an object that contains properties and values. If you only want to output values of the selected properties you must use -Expand or member access ($servers.Name).

How to pass AD computer names to array?

I am trying to Set-ADComputer on all machines matching the filter that is added to the $servers array. But it's not working. I guess it has something to do with passing an object to a string, but I can't get my head around it. Anyone's got a golden tip?
#Get gateway
$gateway = "MGMT01"
$gatewayObject = Get-ADComputer -Identity $gateway
#Get servers
$servers=#(Get-ADComputer -Filter {OperatingSystem -like "Windows Server*"} -Properties Name | select name | ft -HideTableHeaders)
#Create list of servers
Out-File -FilePath c:\adcomputers.txt -InputObject $servers
#Set WAC delegation
ForEach ($server in $servers)
{
$nodeObject = Get-ADComputer -Identity $server
Set-ADComputer -Identity $nodeObject -PrincipalsAllowedToDelegateToAccount $gatewayObject
}
Errors:
Get-ADComputer : Cannot bind parameter 'Identity'. Cannot convert the "Microsoft.PowerShell.Commands.Internal.Format.FormatEndData" value of type "Microsoft.PowerShell.C
ommands.Internal.Format.FormatEndData" to type "Microsoft.ActiveDirectory.Management.ADComputer".
At C:\Users\SA.****\Desktop\inventorize-honolulu-incl-sso.ps1:7 char:40
+ $nodeObject = Get-ADComputer -Identity $server
+ ~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-ADComputer], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.ActiveDirectory.Management.Commands.GetADComputer
Set-ADComputer : Cannot validate argument on parameter 'Identity'. The argument is null. Provide a valid value for the argument, and then try running the command again.
At C:\Users\SA.****\Desktop\inventorize-honolulu-incl-sso.ps1:8 char:26
+ Set-ADComputer -Identity $nodeObject -PrincipalsAllowedToDelegateToAc ...
+ ~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Set-ADComputer], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.ActiveDirectory.Management.Commands.SetADComputer
To output your list of servers to a text file, all you need is this:
Get-ADComputer -Filter {OperatingSystem -like "Windows Server*"} |
Select-Object -ExpandProperty Name |
Out-File "c:\adcomputers.txt"
Bill_Stewart had the right idea, it just didn't fit in exactly with the way you're doing things.
It's the ft -HideTableHeaders that's messing up your array. Use select -ExpandProperty instead:
$servers=#(Get-ADComputer -Filter {OperatingSystem -like "Windows Server*"} -Properties Name | select -ExpandProperty name)
That will give you an array of plain strings, as you seem to want.
Your Get-ADComputer line is an expression problem, you are missing () in {}. Your example works fine after fixing that.
$servers=#(Get-ADComputer -Filter {(OperatingSystem -like "Windows Server*")} -Properties Name | select name | ft -HideTableHeaders)

Issues running Powershell Get-ADComputer in a loop

This is driving me crazy. I'm a beginner at Powershell, but I can't see what's wrong here.
I'm basically running a script which goes off and checks the description field in AD, looks for a match for the user input and pulls back the PC name and the associated description. As below:
import-module activedirectory
$User = Read-Host -Prompt "Enter User's First OR Surname OR partial String"
$User = '*' + $User + '*'
Get-ADComputer -Filter 'Description -like $User' -Properties Description | Select Name, Description
write-Host "================================================================="
}
This on it's own works fine. However I want to loop this until it is closed, so the user can do another search straight away. When I put this into a loops, the first time the search is ran, no results are returned. The 2nd time the first lot of results are returned with the 2nd lot. From then on it works as normal.
So the output looks something like:
Enter User's First OR Surname OR partial String: Test
=================================================================
Enter User's First OR Surname OR partial String: Test
Name Description
---- -----------
COMPXXX01 Test, PS
COMPXXX01 Test, PS
=================================================================
So essentially the first lot of results come through on the second run.
I've tried a few ways of looping for example:
import-module activedirectory
While($true)
{
$User = Read-Host -Prompt "Enter User's First OR Surname OR partial String"
$User = '*' + $User + '*'
Get-ADComputer -Filter 'Description -like $User' -Properties Description | Select Name, Description
write-Host "================================================================="
}
Any advice would be greatly received.
Thanks
Interesting find. As far as I can tell there is some sort of bug with the console & Get-ADComputer. The Get-Adcomputer does "work" in getting the info (put in a variable and the contents show there) but will not output. Funny if you put the output twice it will work the 2nd time:
While($true)
{
$User = Read-Host -Prompt "Enter User's First OR Surname OR partial String"
$User = '*' + $User + '*'
Get-ADComputer -Filter 'Description -like $User' -Properties Description | Select Name, Description
Get-ADComputer -Filter 'Description -like $User' -Properties Description | Select Name, Description
write-Host "================================================================="
}
A work around would be to have a flag for the 1st time:
$firstTime = $true
While($true)
{
$User = Read-Host -Prompt "Enter User's First OR Surname OR partial String"
$User = '*' + $User + '*'
$computerTable = Get-ADComputer -Filter 'Description -like $User' -Properties Description | Select Name, Description
if($firstTime){
$firstTime = $false
$computerTable
}
$computerTable
write-Host "================================================================="
}

How do I add a user to multiple groups

I want to specify a source user and capture the list of the groups that user belongs to. I want to then specify a second user and have the original captured groups added to the new users account.
If user1 is a member of GroupA, GroupB, GroupC I want the script to capture that and add it to user3 when I type his name.
Import-Module ActiveDirectory
$SourceUser = Read-Host -Prompt 'Enter the username of the user whos groups you would like to copy'
$DestUser = Read-Host -Prompt "Enter the username of the user who will get: $SourceUser groups"
$SourceGroups = Get-ADUser $SourceUser -Property MemberOf | % {
$_.MemberOf | Get-ADGroup | select Name | sort name
}
"List of groups for user $DestUser BEFORE script: "
Get-ADUser $DestUser -Property MemberOf | % {
$_.MemberOf | Get-ADGroup | select Name | sort name
}
# ***Where my problem is***
#Add-ADGroupMember $SourceGroups –Member $DestUser
"List of groups for user $DestUser AFTER script: "
Get-ADUser -Identity $DestUser -Property MemberOf | % {
$_.MemberOf | Get-ADGroup | select Name | sort name
}
When in doubt, read the documentation.
Syntax
Add-ADGroupMember [-Identity] <ADGroup> [-Members] <ADPrincipal[]> ...
The -Identity parameter (the first argument) takes a single group identity, not a list of identities. To add a user to a list of groups you need a loop:
$SourceGroups | ForEach-Object { Add-ADGroupMember $_ –Member $DestUser }
Here is the corrected code that now works.
$T2FolderExists = Test-Path "C:\T2\"
$LogsFolderExists = Test-Path "C:\T2\Logs\"
IF ($T2FolderExists -eq $False)
{
New-Item C:\T2\ -type directory
IF ($LogsFolderExists -eq $False)
{
New-Item C:\T2\Logs\ -type directory
}
ELSE
{
}
"`n"
Start-Transcript -Path C:\T2\Logs\CopyMembershipFromADAccount.txt -Append
"`n"
}
ELSE
{
"`n"
Start-Transcript -Path C:\T2\Logs\CopyMembershipFromADAccount.txt -Append
"`n"
}
<#*****Session Paramaters*****>
Set-ExecutionPolicy Unrestricted -force
Import-Module ActiveDirectory
Clear-Host
Write-Host "Enter the username of the user whos groups you would like to copy" -foregroundcolor Green -backgroundcolor Black
$SourceUser = Read-Host
"`n"
Write-Host "Enter the username of the user who will get: $SourceUser groups" -foregroundcolor Green -backgroundcolor Black
$DestUser = Read-Host
"`n"
$SourceGroups = Get-ADUser $SourceUser -Property MemberOf | ForEach-Object {
$_.MemberOf | Get-ADGroup | select Name -ExpandProperty Name | sort name
}
"`n`n"
Write-Host "List of groups for user $SourceUser BEFORE script: "
Get-ADUser $SourceUser -Property MemberOf | ForEach-Object {
$_.MemberOf | Get-ADGroup | select Name -ExpandProperty Name | sort name
}
"`n`n"
Write-Host "List of groups for user $DestUser BEFORE script: "
Get-ADUser $DestUser -Property MemberOf | ForEach-Object {
$_.MemberOf | Get-ADGroup | select Name -ExpandProperty Name | sort name
}
"`n`n"
ForEach ($Group in $SourceGroups)
{
Add-ADGroupMember $Group –Member $DestUser
Write-Host "Adding $Group to $DestUser 's Account" -foregroundcolor Cyan -backgroundcolor Black
}
"`n`n"
Write-Host "List of groups for user $SourceUser BEFORE script: "
Get-ADUser $SourceUser -Property MemberOf | ForEach-Object {
$_.MemberOf | Get-ADGroup | select Name -ExpandProperty Name | sort name
}
"`n`n"
Write-Host "List of groups for user $DestUser AFTER script: "
Get-ADUser $DestUser -Property MemberOf | ForEach-Object {
$_.MemberOf | Get-ADGroup | select Name -ExpandProperty Name | sort name
}
"`n"
Stop-Transcript
Exit
This is what I did:
Import-Module ActiveDirectory
Import-CSV "data.csv" -Delimiter ";" |
ForEach {`
$_.Group1,$_.Group2,$_.Group3,$_.Group4,$_.Group5,$_.Group6 |
Add-ADGroupMember `
-Members $_.Alias`
}
You can have more groups in the script without using them.
And in the "data.csv", you put this (for example):
Alias;Group1;Group2;Group3;Group4
l.salvador;Spanish;Republic;Central;WWW
Although I had an error with "Identity" could not be checked, it worked.

Powershell array of list objects

I am trying to write a script which takes a text file of f5 LTM results and puts this into a searchable array so i can compare results from yesterday to today.
This is an example of the file;
MemberCount : 2
Name : /Common/blah1
Availability : AVAILABILITY_STATUS_GREEN
Enabled : ENABLED_STATUS_ENABLED
Status : The pool is available
MemberCount : 2
Name : /Common/blah2
Availability : AVAILABILITY_STATUS_GREEN
Enabled : ENABLED_STATUS_ENABLED
Status : The pool is available
So ideally I would like to make Name the unique field and the sort the list so i can compare the changes in status from yesterday to today.
Here is the code I am working on to email the results but it only provides line by line difference where I would rather get the object changes in the email.
Add-PSSnapIn iControlSnapIn
$f5_hosts = '192.168.x.x', '192.168.x.x'
$uid = 'xx'
$pwd ='xx'
foreach($f5_host in $f5_hosts){
$f5_host_out = $(get-date -f yyyyMMdd)+"_"+$f5_host+".txt"
$f5_host_out_yesterday = $((get-date).AddDays(-1).ToString('yyyyMMdd'))+"_"+$f5_host+".txt"
#Check login details and generate LTM output file for $f5_host
Initialize-F5.iControl -HostName $f5_host -Username $uid -password $pwd
Get-F5.LTMPool | out-file $f5_host_out
#// Check if EMP file for yesterday exists and send results else send error
if (Test-Path $f5_host_out_yesterday){
$f5_host_Result = compare-object -ReferenceObject (Get-Content $f5_host_out) -DifferenceObject (Get-Content $f5_host_out_yesterday )
$f5_host_out_yesterday+": file is Present!"
$Text_Body = $f5_host+": difference `r`n"
$Text_Body += ($f5_host_Result | out-string)
Send-MailMessage -to simon.thomason#racq.com.au -from simon.thomason#racq.com.au -subject $f5_host+": F5 Daily LTM Check" -body $Text_Body -smtpserver mailrelay.racqgroup.local
}else{
$f5_host_out_yesterday+": is not file is Present!"
Send-MailMessage -to simon.thomason#racq.com.au -from simon.thomason#racq.com.au -subject $f5_host+": Check failed" -body "Yesterday's file is not present" -smtpserver mailrelay.racqgroup.local
}
}
#Limit File retention to 30days.
$limit = (Get-Date).AddDays(-30)
#Get script location
$path = Get-Location
# Delete files older than the $limit.
Get-ChildItem -Path $path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit } | Remove-Item -Force
So as an output I would just want to see something like this in a email
Difference From yesterday to today
Yesterday
MemberCount : 2
Name : /Common/blah1
Availability : AVAILABILITY_STATUS_GREEN
Enabled : ENABLED_STATUS_ENABLED
Status : The pool is available
Today
MemberCount : 2
Name : /Common/blah1
Availability : AVAILABILITY_STATUS_RED
Enabled : ENABLED_STATUS_ENABLED
Status : The pool is available
Ok, on your second question, exporting and importing passwords, the encryption is done per user (and I'm pretty sure per machine), so you can't export it, and then have another account import it, but for just straight saving an encrypted password you can use these functions:
Function Out-EncryptedPasswordFile{
[cmdletbinding()]
Param(
[Parameter(Mandatory = $true)]
[string]$Password,
[Parameter(Mandatory = $true)]
[ValidateScript({If(Test-Path (Split-Path $_)){$true}else{Throw "Unable to create file, directory '$(Split-Path $_)\' does not exist."} })][String]$Path
)
ConvertTo-SecureString -AsPlainText $Password -Force | ConvertFrom-SecureString | Set-Content $Path -Encoding Unicode
}
#Usage Example
#Out-EncryptedPasswordFile TestP#ssw0rd c:\temp\password.txt
Function Import-EncryptedPasswordFile{
[cmdletbinding()]
Param(
[Parameter(Mandatory = $true)]
[ValidateScript({Test-Path $_})][string]$Path
)
$SSPassword = Get-Content $Path | ConvertTo-SecureString
$Ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($SSPassword)
[System.Runtime.InteropServices.Marshal]::PtrToStringUni($Ptr)
[System.Runtime.InteropServices.Marshal]::ZeroFreeCoTaskMemUnicode($Ptr)
}
#Usage Example
#Import-EncryptedPasswordFile C:\temp\password.txt
not certain if right or wrong but this gave the result I was looking for. json was just used so I could store the object and convert it back to powershell object.
Add-PSSnapIn iControlSnapIn
$f5_hosts = 'x.x.x.x', 'x.x.x.x'
$uid = 'xx'
$pwd ='xx'
foreach($f5_host in $f5_hosts){
$f5_host_out = $(get-date -f yyyyMMdd)+"_"+$f5_host+".json"
$f5_host_out_yesterday = $((get-date).AddDays(-1).ToString('yyyyMMdd'))+"_"+$f5_host+".json"
#Check login details and generate LTM output file for $f5_host
Initialize-F5.iControl -HostName $f5_host -Username $uid -password $pwd
Get-F5.LTMPool | ConvertTo-Json | out-file $f5_host_out
#// Check if EMP file for yesterday exists and send results else send error
if (Test-Path $f5_host_out_yesterday){
$f5_host_json_today = Get-Content -Raw $f5_host_out | ConvertFrom-Json
$f5_host_json_yesterday = Get-Content -Raw $f5_host_out_yesterday | ConvertFrom-Json
$f5_host_Result = Compare-Object -ReferenceObject ($f5_host_json_today | Sort-Object ) -DifferenceObject ($f5_host_json_yesterday | Sort-Object ) -property MemberCount, Name, Status, Availability, Enabled, Status | sort-object -property Name
#$f5_host_Result
$f5_host_out_yesterday+": file is Present!"
$Text_Body = $f5_host+": difference `r`n"
$Text_Body += ($f5_host_Result | out-string)
Send-MailMessage -to y#x -from y#x -subject $f5_host+": F5 Daily LTM Check" -body $Text_Body -smtpserver blah
}else{
$f5_host_out_yesterday+": is not file is Present!"
Send-MailMessage -to y#x -from y#x -subject $f5_host+": Check failed" -body "Yesterday's file is not present" -smtpserver blah
}
}
#Limit File retention to 30days.
$limit = (Get-Date).AddDays(-30)
#Get script location
$path = Get-Location
# Delete files older than the $limit.
Get-ChildItem -Path $path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit } | Remove-Item -Force

Resources