Remove certain characters from write-host output in Powershell (Get-ADuser) - powershell

I'm comparing users between two domains to make sure users that are disabled in one, are disabled in the other, using these two steps:
Domain 1:
Get-ADUser -SearchBase "OU=ou2,OU=ou1,DC=pre,DC=domain1,DC=com" -Filter * -Properties * | Select-Object Name | Export-Csv -encoding "utf8" Users.csv
Domain 2:
$input = import-csv -path "Users.csv"
ForEach ($User in $input) {
$result = get-aduser -SearchBase "OU=ou2,OU=ou1,DC=pre,DC=domain2,DC=com" -Filter "name -eq '$($User.Name)'" | Select-Object Enabled
If ($result -eq $null) { Write-host -ForegroundColor Yellow $User "Name not found. Please do a manual check"
}
elseif ($result -like '*False*')
{
Write-host -ForegroundColor Red "**" $User "** must be disabled!"
}
else {get-aduser -SearchBase "ou=Users,ou=SCS,ou=All,dc=osit,dc=ad" -Filter "name -eq '$($User.Name)'" -Properties * | Select-Object Name, Enabled}
}
This works, but gives me the following output:
Name Enabled
---- -------
Firstname1 Lastname1 True
#{Name=Firstname2 Lastname2} - Name not found. Please do a manual check
How do I remove "#{Name=" and "}"?
I have tried adding -ExtendProperity to $result, and Replace with no luck. I'm probably doing it wrong..

$User is a custom object (type [pscustomobject], as output by Import-Csv), and #{Name=Firstname2 Lastname2} is its stringified representation[1], because Write-Host stringifies its arguments for display.
Access the .Name property instead to get just the name:
Write-host -ForegroundColor Yellow $User.Name "- Name not found. Please do a manual check"
More idiomatically, using a single expandable string (string interpolation inside "..."):
Write-host -ForegroundColor Yellow "$($User.Name) - Name not found. Please do a manual check"
If you want to include the full object representation as it would appear if you printed it directly to the console, you need Out-String, but note that you'll end up with multi-line output:
Write-host -ForegroundColor Yellow "$($User | Out-String) - Name not found. Please do a manual check"
[1] You can verify this as follows: $user = [pscustomobject] #{ Name = 'Firstname1 LastName1' }; "$user". The output is string #{Name=Firstname1 LastName1}.

Related

Creating Powershell menu Item and calling functions in the menu item

I am trying to combine the below snippets into the existing code for updating user AD attributes.
Add-Type -AssemblyName 'Microsoft.VisualBasic'
Do
{
Write-Host -Object 'Enter a sAMAccountName / Alias "First.Lastname", or nothing (Press Enter) to leave; wildcards and a space separated list are NOT supported.' -ForegroundColor Yellow
$UserInput = [Microsoft.VisualBasic.Interaction]::InputBox('Enter the User AD account to check', 'sAMAccountName / Alias "First.Lastname"', $UserInput)
If ($UserInput)
{
$(ForEach ($Username in $UserInput.Split(' ', [StringSplitOptions]::RemoveEmptyEntries))
{
If ($ADUser = Get-ADUser -Filter { samAccountName -like $UserName } -Properties DisplayName)
{
Write-Verbose -Message "Processing $($ADUser.DisplayName)"
Write-Host "The sAMAccountName $($UserInput) matching to the AD account '$($ADUser.DisplayName)'" -ForegroundColor Green
}
Else
{
Write-Host "Could not find a user with a sAMAccountName matching '$($UserName)' !" -ForegroundColor Red | Write-Warning
}
})
}
}
Until (-not $UserInput)
The snippets above are working for validating user input against the Active Directory user account, to see if the AD account is valid or not.
This is the main menu item code which is used for updating the AD attributes based on the https://answers.microsoft.com/en-us/msoffice/forum/msoffice_o365admin-mso_exchon-mso_o365b/recipient-type-values/7c2620e5-9870-48ba-b5c2-7772c739c651
# Set The attributes value for Remote Regular User Mailboxes
$replace = #{
msExchRemoteRecipientType = 4
msExchRecipientDisplayType = -2147483642
msExchRecipientTypeDetails = 2147483648
}
# Set The attributes value for Remote Shared Mailboxes
$replace = #{
msExchRemoteRecipientType = 100
msExchRecipientDisplayType = -2147483642
msExchRecipientTypeDetails = 34359738368
}
Set-ADUser -Identity $ADUser -Replace $replace -WhatIf
This is the main menu item code, but without the input check validation section:
If (!(Get-Module "*ActiveDirectory*")) {
Try { Import-Module ActiveDirectory -ErrorAction Stop }
Catch { Write-Warning "Unable to load Active Directory module because $($Error[0])"; Exit }
}
Add-Type -AssemblyName 'Microsoft.VisualBasic'
$Input = [Microsoft.VisualBasic.Interaction]::InputBox('Enter the User AD account to check', 'sAMAccountName / Alias "First.Lastname"', $Input)
$properties = 'Name,msExchRemoteRecipientType,msExchRecipientDisplayType,msExchRecipientTypeDetails,proxyAddresses' -split ','
$ADUserAttributesValues = Get-ADUser -identity $Input -Properties $properties |
Select-Object Name,
msExchRemoteRecipientType,
msExchRecipientDisplayType,
msExchRecipientTypeDetails
$menuCaption = "Hybrid AD User account Exchange attribute modification"
$menuMessage = "Please select the action to be applied to the user $($Input) `n $($ADUserAttributesValues)"
## Format: "Menu Text" = "Help Text"
## "Menu Text" must match the options in the Switch statement below
## "&" marks the character to use as hotkey
$menu = [ordered]#{
'Remote &Shared Mailbox' = "Convert $($Input) as Remote Shared Mailbox"
'Remote &User Mailbox' = "Convert $($Input) as Remote User Mailbox"
'&Quit' = 'Leave without changes'
}
$menuChoices = #()
$menu.Keys | ForEach-Object {
$choice = [System.Management.Automation.Host.ChoiceDescription]$_
$choice.HelpMessage = $menu[$_]
$menuChoices += $choice
}
$answer = $host.UI.PromptForChoice($menuCaption , $menuMessage , $menuChoices, ($menu.Count - 1))
Switch ($menuChoices[$answer].Label) {
'Remote &Shared Mailbox' {
Clear-Host
Write-Host "You selected to convert $($Input) as Remote Shared Mailbox" -ForegroundColor Yellow
# Set The attributes value for Remote Shared Mailboxes
$replace = #{
msExchRemoteRecipientType = 100
msExchRecipientDisplayType = -2147483642
msExchRecipientTypeDetails = 34359738368
}
Set-ADUser -Identity $ADUserAttributesValues.Name -Replace $replace -WhatIf
# Check the attributes value
Get-ADUser -identity $Input -Properties $properties |
Select-Object Name,
msExchRemoteRecipientType,
msExchRecipientDisplayType,
msExchRecipientTypeDetails,
(#{Label = 'Email Address'; Expression = {($_.proxyAddresses | Where-Object {($_ -like 'SMTP*') -and ($_ -notlike '*onmicrosoft.com') } | Sort-Object -CaseSensitive -Descending | ForEach-Object {$_.Split(':')[1]}) -join ', ' }})
}
'Remote &User Mailbox' {
Clear-Host
Write-Host "You selected to convert $($Input) as Remote User Mailbox" -ForegroundColor Yellow
# Set The attributes value for Remote Regular User Mailboxes
$replace = #{
msExchRemoteRecipientType = 4
msExchRecipientDisplayType = -2147483642
msExchRecipientTypeDetails = 2147483648
}
Set-ADUser -Identity $ADUserAttributesValues.Name -Replace $replace -WhatIf
# Check the attributes value
Get-ADUser -identity $Input -Properties $properties |
Select-Object Name,
msExchRemoteRecipientType,
msExchRecipientDisplayType,
msExchRecipientTypeDetails,
(#{Label = 'Email Address'; Expression = {($_.proxyAddresses | Where-Object {($_ -like 'SMTP*') -and ($_ -notlike '*onmicrosoft.com') } | Sort-Object -CaseSensitive -Descending | ForEach-Object {$_.Split(':')[1]}) -join ', ' }})
}
default {
Write-Host 'Goodbye' -ForegroundColor Green
Exit
}
}
So how to combine it to the above?
The code above was created as a rough menu item with lots of repetitions, but it works. I believe it can be optimized by creating functions, but not sure how since the attributes are different.
It is a best practice for Functions to do one thing and one the well.
You then assign the function to your UI design objects.
As for the first part of your post. You cannot do this...
Write-Host "Could not find a user with a sAMAccountName matching '$($env:USERNAME)' !" -ForegroundColor Red | Write-Warning
... it will only return the red text never the warning at all.
Write-Host clears the buffer and thus cannot be used to send results down the
pipeline.
Also, you are literally calling for two warnings for the same code line/string text (one in a red color then the default Write-Warning cmdlet color). So, that's not a thing.
The Write-Warning cmdlet already generates a default color for it, which you cannot change directly. So, just use this...
Write-Warning -Message "Could not find a user with a sAMAccountName matching '$($Username)' !"
... or you have to create your own function to handle colorized text, leveraging stuff like this...
# Colors in the consolehost
$host.UI.RawUI
$host.PrivateData
$host.PrivateData.ConsolePaneTextBackgroundColor
$host.PrivateData.ConsolePaneForegroundColor
# In the ISE
$host.UI.RawUI
[enum]::GetNames([System.ConsoleColor])
$psise.Options.ConsolePaneForegroundColor
# Using .Net
[System.Windows.Media.Colors]
[System.Windows.Media.Colors]::White
[enum]::GetNames([System.ConsoleColor])
[enum]::GetNames([System.ConsoleColor])[0]
$psise.Options
$psise.Options.ConsolePaneForegroundColor
... when using cmldets that don't have color like Write-Output, which is pipeline friendly. You can create your own GUI message boxes/forms to have more control.
Why are you doing this -WhatIf here?
Set-ADUser -Identity $ADUserAttributesValues.Name -Replace $Replace -WhatIf
If this is live code, then this Set-* will never happen and thus makes everything below it is moot, because nothing has changed. Unless what you are posting is your test/debug/OpsCheck code, then this is prudent.
You have this ...
# Check the attributes value
Get-ADUser -identity $UserInput -Properties $MailProperties |
Select-Object Name,
msExchRemoteRecipientType,
msExchRecipientDisplayType,
msExchRecipientTypeDetails,
(#{Label = 'Email Address'; Expression = {
($_.proxyAddresses |
Where-Object {($_ -like 'SMTP*') -and
($_ -notlike '*onmicrosoft.com')
} |
Sort-Object -CaseSensitive -Descending |
ForEach-Object {$_.Split(':')[1]}) -join ', ' }})
}
... shown twice. Just make it a separate function and call it as needed
So, the below is untested, since I am not anywhere near a lab to try this.
Note:
I am using PowerShell's natural line breaks to ensure code readability and not be so long.
There are times when long lines cannot be avoided, but whenever possible, if your code line won't fit on a normal 8.5x11.5 sheet of paper like a normal Word doc or book, then it is too long and a target for refactoring, using natural line breaks, splatting, hash tables, PSCustomerObjects, etc.
Refactored code: Again, I am not in my AD/Exchange lab environment, so I useg Localuser cmdlets for a quick and dirty code test.
(personally I'd put this is a single user form using the PowerShell Help and avoid all the menuing stuff altogether - see this: Poor Man’s GUI or create a custom form using https://poshgui.com.
Add-Type -AssemblyName 'Microsoft.VisualBasic'
<#
Using PowerShell StrictMode Option force code compliance
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/set-strictmode?view=powershell-7
#>
$UserInput = $null
$ADUser = $null
$MailProperties = $null
$ADUserAttributesValues = $null
$MenuCaption = $null
$MenuMessage = $null
$Menu = $null
$MenuChoices = $null
$UserAnswer = $null
$choice = $null
$MenuChoices = $null
$MenuCaption = $null
$MenuMessage = $null
$MenuChoices = $null
$ReplaceValue = $null
Function Get-ADAttributesValue
{
[CmdletBinding(SupportsShouldProcess)]
[Alias('gaav')]
Param
(
)
# Check the attributes value
Get-ADUser -identity $UserInput -Properties $MailProperties |
Select-Object Name,
msExchRemoteRecipientType,
msExchRecipientDisplayType,
msExchRecipientTypeDetails,
(#{Label = 'Email Address'; Expression = {
($PSitem.proxyAddresses |
Where-Object {($PSitem -like 'SMTP*') -and
($PSitem -notlike '*onmicrosoft.com')
} |
Sort-Object -CaseSensitive -Descending |
ForEach-Object {$PSitem.Split(':')[1]}) -join ', ' }})
}
$MailProperties = 'Name,
msExchRemoteRecipientType,
msExchRecipientDisplayType,
msExchRecipientTypeDetails,
proxyAddresses' -split ','
Do
{
Write-Host -Object 'Enter a samAccountName / Alias "First.Lastname", or nothing (Press Enter) to leave; wildcards and a space-separated list are NOT supported.' -ForegroundColor Yellow
$UserInput = [Microsoft.VisualBasic.Interaction]::
InputBox(
'Enter the User AD account to check',
'Name / Alias "First.Lastname"',
$UserInput
)
If ($UserInput)
{
$(ForEach ($Username in $UserInput.Split(' ', [StringSplitOptions]::RemoveEmptyEntries))
{
If ($ADUser = Get-ADuser -Filter { samAccountName -like $UserName } -Properties Name)
{
Write-Verbose -Message "Processing $($ADUser.Name)"
Write-Host "The samAccountName $($UserInput) matching to the AD account '$($ADUser.Name)'" -ForegroundColor Green
}
Else {Write-Warning -Message "Could not find a user with a samAccountName matching '$($UserName)' !"}
})
}
}
Until (-not $UserInput)
If (!(Get-Module "*ActiveDirectory*"))
{
Try { Import-Module ActiveDirectory -ErrorAction Stop }
Catch
{
Write-Warning "Unable to load Active Directory module because $($Error[0])"
Exit
}
}
$UserInput = [Microsoft.VisualBasic.Interaction]::
InputBox(
'Enter the User AD account to check',
'Name / Alias "First.Lastname"',
$UserInput
)
$ADUserAttributesValues = Get-ADUser -identity $Input -Properties $properties |
Select-Object Name,
msExchRemoteRecipientType,
msExchRecipientDisplayType,
msExchRecipientTypeDetails
$MenuCaption = "Hybrid AD User account Exchange attribute modification"
$MenuMessage = "Please select the action to be applied to the user $($UserInput) `n $($ADUserAttributesValues)"
## Format: "Menu Text" = "Help Text"
## "Menu Text" must match the options in the Switch statement below
## "&" marks the character to use as hotkey
$Menu = [ordered]#{
'Remote &Shared Mailbox' = "Convert $($UserInput) as Remote Shared Mailbox"
'Remote &User Mailbox' = "Convert $($UserInput) as Remote User Mailbox"
'&Quit' = 'Leave without changes'
}
$MenuChoices = #()
$Menu.Keys |
ForEach-Object {
$choice = [System.Management.Automation.Host.ChoiceDescription]$PSitem
$choice.HelpMessage = $Menu[$PSitem]
$MenuChoices += $choice
}
$UserAnswer = $host.UI.PromptForChoice(
$MenuCaption ,
$MenuMessage ,
$MenuChoices,
($Menu.Count - 1)
)
Switch ($MenuChoices[$UserAnswer].Label)
{
'Remote &Shared Mailbox' {
Clear-Host
Write-Host "You selected to convert $($UserInput) as Remote Shared Mailbox" -ForegroundColor Yellow
# Set The attributes value for Remote Shared Mailboxes
$ReplaceValue = #{
msExchRemoteRecipientType = 100
msExchRecipientDisplayType = -2147483642
msExchRecipientTypeDetails = 34359738368
}
# Set-ADUser -Identity $ADUserAttributesValues.Name -Replace $ReplaceValue -WhatIf
Get-ADAttributesValue
}
'Remote &User Mailbox' {
Clear-Host
Write-Host "You selected to convert $($UserInput) as Remote User Mailbox" -ForegroundColor Yellow
# Set The attributes value for Remote Regular User Mailboxes
$ReplaceValue = #{
msExchRemoteRecipientType = 4
msExchRecipientDisplayType = -2147483642
msExchRecipientTypeDetails = 2147483648
}
# Set-ADUser -Identity $ADUserAttributesValues.Name -Replace $ReplaceValue -WhatIf
Get-ADAttributesValue
}
default
{
Write-Host 'Goodbye' -ForegroundColor Green
Exit
}
}
Update
As for:
"the script above you've submitted stuck in the Do Until (-not
$UserInput) loop :-) "
As does yours. ;-}
Be sure to pay attention to when to use assignment operators '=' vs comparison operators '-eq'.
Simply, that is because that is what you wrote it to do. I did not address that part as that was not part of your request. Your code specifically will not exit until you pass it an empty string. The input will always be equal.
So, if you are saying it should exit if the name is not found or the like then that is what you have to add to your code. Also, you are using -Like and that needs a wildcard string, otherwise use -eq.
In that 'get request', you should pipe to select-object -Properties or use dot property.
Also, you are instructing the user to only enter one name, but your code is looking for an array. Why?
Lastly in your 'get request', you are only asking for one property, so no others are available, so, there is no need for the Dot property later.
So, I'd refactor the do loop this way...
(Again, there are other ways (like Try/Catch/Finally with or without the Begin/Process/End blocks)
... this is just one.
Add-Type -AssemblyName PresentationCore,PresentationFramework
Add-Type -AssemblyName System.Drawing
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName Microsoft.VisualBasic
$MsgText = '
Enter a sAMAccountName / Alias as First.Lastname
Wildcards and a space-separated list are NOT supported.
To quit, enter nothing and click OK.'
$d = [Windows.Forms.MessageBox]::show($MsgText, 'User Instrutions',
[Windows.Forms.MessageBoxButtons]::YesNo,
[Windows.Forms.MessageBoxIcon]::Information)
Do
{
$UserInput = $null
If ($d -eq [Windows.Forms.DialogResult]::Yes)
{
# Show inputbox for user to enter a single username
$UserInput = [Microsoft.VisualBasic.Interaction]::
InputBox(
'Enter the User AD account to check',
'sAMAccountName / Alias "First.Lastname"',
$UserInput
)
}
else
{
Write-Warning -Message 'You decided to exit the requested action'
Break
}
# ForLoop??? --- Why are you checking for an array, when you are only asking for one entry at a time?
If ($UserInput -eq (Get-LocalUser | Where-Object Name -eq $UserInput))
{Write-Host "Processing $UserInput" -ForegroundColor DarkYellow}
Else{Write-Warning -Message "Could not find a user with a Name matching $UserInput ! Try again."}
}
Until (-not $UserInput)
# Results when cancelling the instructions box
<#
WARNING: You decided to exit the requested action
#>
# Results from the inputbox
<#
WARNING: Could not find a user with a Name matching test ! Try again.
WARNING: Could not find a user with a Name matching admin ! Try again.
Processing administrator
WARNING: Could not find a user with a Name matching gues ! Try again.
Processing guest
WARNING: Could not find a user with a Name matching ! Try again.
#>
More code is needed to handle the output of the OK/Cancel button, when and if the input is null or cancel is used. For example the Try/Catch I spoke of earlier.
Again popping GUIs, then sending stuff to the console is a very bad user experience. Stay consistent, pick one or the other. Again, us a single GUI form for this, send user instructions and info to the body of that form.
If you want to combine the code snippets using helper functions, here's an idea for you:
if (!(Get-Module "*ActiveDirectory*")) {
Try { Import-Module ActiveDirectory -ErrorAction Stop }
Catch { Write-Warning "Unable to load Active Directory module because $($Error[0])"; Exit }
}
# function to ask the user which user to update.
# returns either a valid AD including mailbox attributes user or nothing at all
function Prompt-User {
Add-Type -AssemblyName 'Microsoft.VisualBasic'
# enter an endless loop
while ($true) {
Clear-Host
$msg = "Enter the User AD account to check.`r`n`r`nWildcards and a space separated list are NOT supported."
Write-Host $msg -ForegroundColor Yellow
$account = [Microsoft.VisualBasic.Interaction]::InputBox($msg, 'sAMAccountName / Alias "First.Lastname"')
# exit the function if the user entered nothing or whitespace only
if ([string]::IsNullOrWhiteSpace($account)) { return }
$properties = 'DisplayName','msExchRemoteRecipientType','msExchRecipientDisplayType','msExchRecipientTypeDetails'
$ADUser = Get-ADUser -Filter "samAccountName -like '$account'" -Properties $properties -ErrorAction SilentlyContinue
if ($ADUser) {
Write-Host "The sAMAccountName $($account) matches the AD account '$($ADUser.DisplayName)'" -ForegroundColor Green
return $ADUser
}
else {
Write-Warning "Could not find a user with a sAMAccountName matching '$($account)' ! Please try again."
}
}
}
# function to ask the user what action to undertake
function Prompt-Action ([Microsoft.ActiveDirectory.Management.ADUser]$ADUser) {
$menuCaption = "Hybrid AD User account Exchange attribute modification"
$menuMessage = "Please select the action to be applied to the user $($ADUser.Name)"
## Format: "Menu Text" = "Help Text"
## "Menu Text" must match the options in the Switch statement below
## "&" marks the character to use as hotkey
$menu = [ordered]#{
'Remote &Shared Mailbox' = "Convert $($Input) as Remote Shared Mailbox"
'Remote &User Mailbox' = "Convert $($Input) as Remote User Mailbox"
'&Quit' = 'Leave without changes'
}
$menuChoices = $menu.Keys | ForEach-Object {
$choice = [System.Management.Automation.Host.ChoiceDescription]$_
$choice.HelpMessage = $menu[$_]
$choice
}
$answer = $host.UI.PromptForChoice($menuCaption , $menuMessage , $menuChoices, ($menu.Count - 1))
return ($menuChoices[$answer].Label -replace '&') # removing the '&' makes processing later easier
}
# function to display users Mailbox attributes
function Get-UserMailboxDetails ([string]$DistinguishedName) {
$properties = 'msExchRemoteRecipientType','msExchRecipientDisplayType','msExchRecipientTypeDetails','proxyAddresses'
Get-ADUser -Identity $DistinguishedName -Properties $properties -ErrorAction SilentlyContinue |
Select-Object msExchRemoteRecipientType,
msExchRecipientDisplayType,
msExchRecipientTypeDetails,
#{Label = 'Email Address'; Expression = {
($_.proxyAddresses | Where-Object {($_ -like 'SMTP*') -and ($_ -notlike '*onmicrosoft.com') } |
Sort-Object -CaseSensitive -Descending | ForEach-Object {$_.Split(':')[1]}) -join ', ' }}
}
# checks the current user mailbox type
# returns 'Remote User Mailbox', 'Remote Shared Mailbox' or 'Other'
function Check-MailboxAttributes ([Microsoft.ActiveDirectory.Management.ADUser]$ADUser) {
if ($ADUser.msExchRemoteRecipientType -eq 4 -and
$ADUser.msExchRecipientDisplayType -eq -2147483642 -and
$ADUser.msExchRecipientTypeDetails -eq 2147483648) { 'Remote User Mailbox' }
elseif (
$ADUser.msExchRemoteRecipientType -eq 100 -and
$ADUser.msExchRecipientDisplayType -eq -2147483642 -and
$ADUser.msExchRecipientTypeDetails -eq 34359738368) { 'Remote Shared Mailbox' }
else { 'Other' }
}
# this is your main code
do {
$ADUser = Prompt-User
if ($ADUser) {
Clear-Host
# here is where you process the user
$action = Prompt-Action $ADUser
if ($action -like 'Remote*') { # either 'Remote Shared Mailbox' or 'Remote User Mailbox'
# do we need to convert the user mailbox type?
if ((Check-MailboxAttributes $ADUser) -eq $action) {
Write-Host "$($ADUser.DisplayName) is already a $action" -ForegroundColor Yellow
}
else {
Write-Host "You selected to convert $($ADUser.DisplayName) as $action" -ForegroundColor Yellow
if ($action -match 'User') {
# create hashtable for Remote Regular User Mailboxes
$newProperties = #{
msExchRemoteRecipientType = 4
msExchRecipientDisplayType = -2147483642
msExchRecipientTypeDetails = 2147483648
}
}
else {
# create hashtable for Remote Shared Mailboxes
$newProperties = #{
msExchRemoteRecipientType = 100
msExchRecipientDisplayType = -2147483642
msExchRecipientTypeDetails = 34359738368
}
}
$ADUser | Set-ADUser -Replace $newProperties
# reload the user and show the resulting mailbox properties
Get-UserMailboxDetails $ADUser.DistinguishedName
}
}
}
} until (-not $ADUser)
# all done
Write-Host 'Goodbye' -ForegroundColor Green
I agree with postanote that I would create a proper GUI for this rather than using Write-Host stuff in the console

Powershell AD-GetComputer with Array Variable

I'm trying to create a loop that tests the connection to specific computers in the Active Directory. The output is #{name=KY-WH-DT01} when I'm looking for KY-WH-DT01. I'm not sure what I'm doing wrong.
As a workaround, I've pulled the list manually and properly inserted it into the variable as hard code.
function testConnection {
$computers = Get-ADComputer -filter 'Name -like "KY-WH*" -or name -like "KY-SR"' | select name
$pass = 0
$fail = 0
foreach ($computer in $computers) {
$testConnection = Test-Path "\\$computer\C$" -ErrorAction Stop
if ($testConnection -eq $true) {
Write-Host $computer -ForegroundColor Green
$pass = $pass + 1
}
else {
Write-Host $computer -ForegroundColor Red -BackgroundColor Black
$fail = $fail + 1
}
}
Write-Host $null
Write-Host "Passed: $pass | Failed: $fail"
}
testConnection
...
This code should output a list of computer names with colors determining whether the connection test passed or failed by turning them either red or green.
You need to drill down a little bit in your variable.
foreach ($computer in $computers.Name) {
This will do it if you only want the name or the computer and no other variable.
You can also change your initial search to include the -ExpandProperty switch and you will not need to dig down into the property.
$computers = Get-ADComputer -filter 'Name -like "KY-WH*" -or name -like "KY-SR"' | select -ExpandProperty name

Powershell - Set-ADUser after Gridview

I've very new to PowerShell and just starting learn. I'm very appreciative for any help.
Here is what I'm after: I would like to set several OUs to search for AD users who have the Dial-In tab selected as True or Null (Control access through NPS Network Policy) and display the results in gridview. the first part of my script is working, at least displaying the correct users in gridview. Once user(s) are selected in gridview pass those user to have their setting changed to False (deny access).
The error I have is: Set-ADUser : Cannot validate argument on parameter 'Identity'. The argument is null.
$OUs = 'OU=Test,DC=Test,DC=net'
$users = $OUs | Foreach {
Get-ADUser -Filter {(msNPAllowDialin -eq $True) -or (msNPAllowDialin -notlike "*")} -SearchBase $_ -Properties msNPAllowDialin,description,SamAccountName |
Select-Object Name,#{Name="BT UserID";Expression={$_.SamAccountName}},Description | Sort-Object name |
Out-GridView -Title "Select One or More Users to Change Setting" -PassThru
}
$user = $users | foreach {
Set-ADUser $user -replace #{msnpallowdialin=$False}
Write-Host "$($_.name) Dial-In Setting Changed" -ForegroundColor cyan
}

Powershell Import-Csv then Get-Aduser results in all users in ad being displayed when a Blank Line appears

I am writing a powershell script to disable users due to the fact that we get a list of them everyday and it is monotonous. I paste the list from the ticket into a csv formatted as Lastname, Firstname then run my script with imports the list, serches ad and ask if you want to disable if it finds them. Here is the code...
# Set variables
$Import = "C:\Scripts\Support Files\Users_To_Disable.csv"
$Export = "C:\Scripts\Support Files\Disabled_Users_Output.txt"
# Import user list
$Users = Import-CSV $Import
foreach ($User in $Users)
{
# Set user variables
$LastName = $User.("Surname")
$FirstName = $User.("GivenName")
# Use user variables from list to search ad
$UserName = (Get-ADUser -Filter "GivenName -like '$FirstName*' -and Surname -like '$LastName*'").SamAccountName
# What to do if it finds nothing
If ($UserName -eq $Null)
{
Write-Host $LastName, $FirstName NA -ForegroundColor Yellow
Write-Output "$LastName, $FirstName NA" | Out-File $Export -Append
}
# What to do if it finds a user
Else
{
# Ask for user input
Write-Host $LastName, $FirstName Found -ForegroundColor Green
Write-Host UserName = $UserName -ForegroundColor Green
DO {
$Disable = Read-Host "Do you want to disable user? (Y/N)"
If($Disable -eq "Y")
{
# Disable the user
Disable-ADAccount -Identity $UserName
# Move the user
Get-ADUser $UserName | Move-ADObject -TargetPath "OU=Disabled - Retention,DC=intranet,DC=sw"
# Add Disabled Users group
Add-ADGroupMember "Disabled Users" -Members "$UserName"
# Set Disable Users as primary group
$Group = Get-ADGroup "Disabled Users" -Properties #("PrimaryGroupToken")
Get-ADUser "$UserName" | Set-ADUser -Replace #{PrimaryGroupID=$Group.PrimaryGroupToken}
# Remove all other groups
$User = Get-ADUser "$UserName" -Properties MemberOf
$Groups = $User.MemberOf |ForEach-Object { Get-ADGroup $_ }
$Groups | ForEach-Object { Remove-ADGroupMember -Identity $_ -Members $User -Confirm:$false }
# Output
Write-Host $LastName, $FirstName Disabled -ForegroundColor Red
Write-Output "$LastName, $FirstName Disabled" | Out-File $Export -Append
Break
}
}
Until ($Disable -eq "N")
}
}
Invoke-Item $Export
All of that works, what is scary is that if there are blank cells above a user then it returns all of the users in ad and asks if you want to disable all of them. In other words if the csv looks like this...
Surname GivenName
User Test
Everything works fine, but if it looks like this...
Surname GivenName
User Test
Pandemonium, well not really but it does ask if you want to initiate a resume generating event, which I don't so how can I build in some safety that would stop it from returning all of ad when there are blanks in the csv before users?
You can eliminate the blank lines by filtering out Null values on your import, which should resolve the problem.
$Users = Import-CSV $Import | Where-Object {$_.Surname}

Get-Aduser from a prompt for First and Last Name with wildcard

Nowhere have I found anyone attempting to prompt for first and last names and then put that into a variable with a wildcard.
If I substitute real values with the asterisk, it works but attempting to do so with a variable returns nothing.
$LastName = Read-Host "Enter user's Last Name"
$FirstName = Read-Host "Enter users's First Name"
$GroupMembershipList = (Get-ADUser -Filter {(GivenName -like $FirstName*) -and (Surname -like $LastName*)}).SAMAccountName
Foreach ($Name in $GroupMembershipList) {
$GroupMemberShip = Get-ADPrincipalGroupMembership -Identity "$Name" | Sort Name |ForEach-Object {$_.name -replace ".*:"}
$FullName = Get-ADUser $Name -Properties * | Select -Property DisplayName
$UserPrincipalName = Get-ADUser $Name -Properties * | Select -Property UserPrincipalName
#Write-Output $PrincipalName
Write-Output $FullName
Write-Output $Name
Write-Output $GroupMembership
Write-Output " "
}
I think the issue is just that your braces are preventing your variables from expanding the way you expect them to.
I offer this since -Filter will work with properly formatted strings as well.
$GroupMembershipList = Get-ADUser -Filter "GivenName -like '$FirstName*' -and Surname -like '$LastName*'" | Select-Object -ExpandProperty SamAccountName
and yes you can just get the property the same was you did before
$GroupMembershipList = (Get-ADUser -Filter "GivenName -like '$FirstName*' -and Surname -like '$LastName*'").SamAccountName
I used the second suggestion and it worked. I am new to PS and also to programming in general.
I find PS confusing at times regarding the placement of parenthesis, brackets, etc. I generally have the logic but mess up on placing these delimiters.
You mentioned formatting my code. I am sorry I don't know what you mean by that.
Also, I would rather use Write-Host to allow for formatting but when I do, all of the data is on a single line and the user returned is specified as #{DisplayName=Doe, John}.
Can you address that or should this be posted to a new subject?
I worked on it more and figured the Write Host stuff. Also added a Do Loop
$ErrorActionPreference = "Stop"
$Continue = "Quit"
Do {
$LastName = Read-Host "Enter user's Last Name"
$FirstName = Read-Host "Enter users's First Name"
$GroupMembershipList = (Get-ADUser -Filter "GivenName -like '$FirstName*' -and Surname -like '$LastName*'").SamAccountName
Foreach ($Name in $GroupMembershipList) {
$GroupMemberShip = Get-ADPrincipalGroupMembership -Identity "$Name" | Sort Name |ForEach-Object {$_.name -replace ".*:"}
Write-Host " "
Write-Host $FirstName, $LastName -ForegroundColor Yellow
Write-Host IMC UserName = $Name
Write-Host "*****************************" -ForegroundColor Red
Write-Host "Groups $Firstname $LastName is a member of:" -ForegroundColor Yellow
$GroupMembership
Write-Host " "
}
$Continue = Read-Host "Do you want to check another name? (Y/N)"
If($Continue -eq "Y"){
}
}
until ($Continue -eq "N")
$GivenName = read-host "What's the users first name (wildcard * ok)?"
$Surname = read-host "What's the users last name (wildcard * ok)?"
Get-ADUser -filter{(Surname -like $Surname -and GivenName -like $GivenName)} -properties GivenName, Surname, UserPrincipalName, mobile