I've created a PS script in the past and I would like it to be more interactive.
This is the script I've created.
$csv = Import-CSV 'C:\Users\w0vlnd\Desktop\Powershells\Computers in a specific workgroup or domain.csv'
$ADprops = #(
'DisplayName'
'Mail'
'LastBadPasswordAttempt'
'AccountExpirationDate'
'PasswordLastSet'
'Enabled'
)
$filter = #(
$ADprops
#{
Name = 'Account active'
Expression = {$Account}
}, #{
Name = 'Password Changeable'
Expression = { $changeable }
}, #{
Name = 'Password Expires'
Expression = { $expires }
}, #{
Name = 'Last logon'
Expression = { $lastlogon }
}, #{
Name = 'PC Name'
Expression = { $pcName }
}, #{
Name = 'System Boot Time'
Expression = { $Boot }
}
)
Clear-Host
do
{
Write-Host "Enter the user ID: " -ForegroundColor Cyan -NoNewline
$UserName = Read-Host
Write-Host ""
#Computer Info#
$pcName = $csv.Where({ $_."User ID" -match $Username })."PC Name"
$boot = SystemInfo /s $pcName | Select-String -Pattern 'System Boot Time'|
ForEach-Object { ($_ -split '\s{2,}')[1] }
#Account and passowrd information#
$Account, $expires, $changeable, $lastlogon = net user $Username /domain |
Select-String -Pattern 'Account active|Password Changeable|Password Expires|Last logon'|
ForEach-Object { ($_ -split '\s{2,}')[1] }
Get-ADUser -Identity $Username -Properties $ADprops |
Select-Object $filter
} while ($Username -notcontains $Processes)
And I want to put it in to this script but I'm figuring out how. As in the first script the user must first fill in the user ID. Afterwards he get should get the options U,P,... Each option should be executing a command. An example of which command you can find in the first script like: #computer info# IF I haver already one command running I'll figure the rest out myself.
How can I do this? Also the menu should come back after the option has been chosen.
Thanks in advance!
param (
[string]$Title = 'UserInfo V3.1'
)
Clear-Host
Write-Host "================ $Title ================"
Write-Host "Press 'U' for general user info."
Write-Host "Press 'P' for account and password information."
Write-Host "Press 'C' computer information."
Write-Host "Press 'G' group memberships."
Write-Host "Press 'R' search for other user ID."
Write-Host "Press 'Q' to Quit."
}
Show-Menu –Title 'UserInfo V3.1'
$selection = Read-Host "Please make a selection"
switch ($selection)
{
'U' {
'You chose option #U'
} 'P' {
'You chose option #P'
} 'C' {
'You chose option #C'
} 'G' {
'You chose option #G'
} 'Q' {
'You chose option #Q'
return
}
I would use a PromptForChoice method, if a user select a wrong option, question will be asked again :
$repeat = $true
while ($repeat)
{
[System.Management.Automation.Host.ChoiceDescription[]]$choicelist =
"&User infos",
"&Account and password infos",
"&Computer infos",
"&Group membership",
"&Search for another user",
"&Quit"
switch ($Host.UI.PromptForChoice("Please select", "What do you want ?", $choicelist, 0))
{
0 {
"User infos here"
break
}
1 {
"Account & password infos here"
break
}
2 {
"Computer infos here"
break
}
3 {
"Group membership infos here"
break
}
4 {
"Search for another user Id here"
break
}
5 {
"Exiting."
$repeat = $false
}
}
}
Notice the & sign before the letter to be used (I have not used same letters as your code). This sign could be used inside the choice text, for example "Account and &password infos" means that you need to use the letter p to select this option.
The value returned by PromptForChoice is the selected index of the choice array.
Related
Hello everyone i need this script to work and i'm stuck with a error.
I need to have a dynamic script with user choice and linking the mailbox we enter in first step to the HR choice.
In the csv part we have a group distribution list
Error says that i can not do the add-distributiongroupmember and i don't know why
can someone help me on this one ?
(I just do the 0 part choice because i need this one to work before doing the other choice)
code below
Connect-ExchangeOnline
$User = Read-Host "Enter Name of the mailbox to add"
Try {
$Mbx = Get-Mailbox -Identity $User -ErrorAction Stop | Select -ExpandProperty PrimarySmtpAddress}
Catch {
Write-Host "No mailbox can be found called" $User; break }
$Services = [System.Management.Automation.Host.ChoiceDescription]::new('&Services')
$Services.HelpMessage = 'Get running services'
$HR = New-Object System.Management.Automation.Host.ChoiceDescription '&HR', 'Get running HRDL'
$Legal = New-Object System.Management.Automation.Host.ChoiceDescription '&Legal', 'Get running LegalDL'
$Quit = New-Object System.Management.Automation.Host.ChoiceDescription '&Quit', 'Quit menu'
$options = [System.Management.Automation.Host.ChoiceDescription[]]($HR, $Legal, $Quit)
$Result = $host.UI.PromptForChoice('Task menu', 'Select a Department', $options , 0 )
$DLs = Import-Csv -Path "C:\Users\GregorySemedo\Desktop\Script\DL\DL-HR.csv"
switch($Result)
{
0 { ForEach ($DL in $DLs) {
Try {
Add-DistributionGroupMember -Identity $DL."HR" -Member $Mbx -ErrorAction Continue }
Catch {
Write-Host "Couldn't add" $Mbx "to DL" (Get-DistributionGroup -Identity $DL."HR").DisplayName }
If($?)
{
Write-Host $User Succesfully added -ForegroundColor Green
}
Else
{
Write-Host $User - Error occurred -ForegroundColor Red
}}
}
}
I am trying to add a user to the Remote Desktop group using Powershell.
It seems it's not breaking the loop and doesn't execute further statements.
Can you please help me where the issue is:
$remote = ""
While($remote -ne "Y" ){
$remote = read-host "Do you need to add anyone to the Remote Desktop group (y/n)?"
Switch ($remote)
{
Y {
$remoteuser = ""
while ( ($remoteuser -eq "") -or ($UserExists -eq $false) )
{
$remoteuser = Read-Host "Enter the username that needs to be in the group"
Write-Host "User inputted $remoteuser"
sleep -Seconds 2
try {
Get-ADUser -Identity $remoteuser -Server <server-FQDN>
$UserExists = $true
Write-Host "$remoteuser found!"
sleep 5
}
catch [Microsoft.ActiveDirectory.Management.ADIdentityResolutionException] {
Write-Host "User does not exist."
$UserExists = $false
}
catch {
Write-Host "Username is blank"
$UserExists = $false
}
}
}
N {Write-Host "No user accounts will be added to the Remote Desktop Users group. Restart your PC."}
default {Write-Host "Only Y/N are Valid responses"}
}
}
<further statements>
I'm trying to create a menu for tasks i run in 365 Exchange. I want the script to return to the main menu once rather then ending when i run it. any guidance would be greatly received
edit - thanks it now loops back to the menu, could you point me in the direction of displaying a the powershell results before heading back to the main menu.
You should properly format your question, the code is unreadable.
A general approach can be like this:
do
{
Show-Menu
$inputChoice = Read-Host "Select your choice"
switch ($inputChoice)
{
'1' {
clear-host
write-Host "The output will be shown onscreen"
get-exomailbox -resultsize 10
pause
} '2' {
write-Host "2"
} 'q' {
return
}
}
}
until ($inputChoice -eq 'q')
Continuing from my comment to highlight come suggestions.
I do not have an M365 instance to test this in, so that side is untested, but this is just to give you another take on your use case approach. Ensure you leverage -WhatIf or -Confirm on those cmdlets to make sure of stuff before you really run things.
Output to the screen is the PowerShell default for text. So, I have a standard of only using Write-* only when it's absolutely needed. Others have their own
take of course.
I am using scriptblock to allow for reusable code to eliminate redundancy. The return to the menu and out of the screen is also in this.
Again, this is just another take on what you've done and what others have noted.
Clear-Host
do
{
Add-Type -AssemblyName System.Drawing,
PresentationCore,
PresentationFramework,
System.Windows.Forms,
Microsoft.VisualBasic
[System.Windows.Forms.Application]::EnableVisualStyles()
$MessageBox = [Microsoft.VisualBasic.Interaction]
$UserEmalAddreess = {
$MessageBox::InputBox(
'Enter Email Address of identity',
'User',
$env:UserName
)
}
$UserEmalAddreessAccess = {
$MessageBox::InputBox(
'Enter Email Address of person who gains/revokes access',
'User',
$env:UserName
)
}
$AddMailboxPermission = {
$AddMailboxPermissionSplat = #{
Identity = (& $UserEmalAddreess)
InheritanceType = 'All'
User = $(& $UserEmalAddreessAccess)
AccessRight = 'FullAccess'
}
Add-MailboxPermission #AddMailboxPermissionSplat
}
$BannerLine = $(('=') * 16)
function Show-Menu
{
param
(
[string]$Title = '365 Exchange Admin'
)
Clear-Host
"$BannerLine $Title $BannerLine"
'1: Connect to PS Exchange Online'
'2: Give Access To MailBox - No AutoMapping'
'3: Give Access To MailBox - With AutoMapping'
'4: Get MailBox Permissions'
'5: Remove MailBox Permissions'
'6: Create A Shared MailBox'
'7: Convert To Shared MailBox'
'8: Get Mailbox Info'
'9: Set New 365 Password'
"Q: Press 'Q' to quit."
}
Show-Menu
$selection = Read-Host Please make a selection
switch ($selection)
{
'1'
{
$MFAExchangeModule = (
(Get-ChildItem -Path $("$env:LOCALAPPDATA\Apps\2.0\") -Filter 'CreateExoPSSession.ps1' -Recurse).FullName |
Select-Object -Last 1
)
. $MFAExchangeModule
Connect-EXOPSSession
}
'2'
{
& $AddMailboxPermission -Automapping $false |
Out-Host
}
'3'
{
& $AddMailboxPermission -Automapping $true |
Out-Host
}
'4'
{
Get-MailboxPermission -Identity $(& $UserEmalAddreess) |
Format-List
}
'5'
{
$RemoveMailboxPermission = #{
Identity = $(& $UserEmalAddreess)
User = $(& $UserEmalAddreessAccess)
AccessRights = 'FullAccess'
InheritanceType = 'All'
}
Remove-MailboxPermission #RemoveMailboxPermission |
Out-Host
}
'6'
{
New-Mailbox -Name $(& $UserEmalAddreess) -Shared |
Out-Host
}
'7'
{
Set-Mailbox $(& $UserEmalAddreess) -Type Shared |
Out-Host
}
'8'
{
Get-Mailbox -Identity $(& $UserEmalAddreess) |
Format-Table Name, RecipientTypeDetails
}
'9'
{
$Creds = Get-Credential -Credential "$env:UserName#$env:USERDNSDOMAIN"
$setMsolUserPasswordSplat = #{
UserPrincipalName = $Creds.UserName
NewPassword = $Creds.GetNetworkCredential().Password
ForceChangePassword = $False
}
Set-MsolUserPassword #setMsolUserPasswordSplat |
Out-Host
}
'Q' {return}
}
}
until ($inputChoice -eq 'q')
My Powershell script has some features/functions implemented, but there are some features that I want to restrict to some users.
In order to allow the current user or a different user to select such restricted features from the menu, I am looking for a way to require user authentication from Windows to continue. How could I do that? How the UserAuthentication function below should be like?
Code:
$feature = Read-Host 'Select the feature by typing the number [1 - 2]'
switch ($feature)
{
1
{
write-output "This feature any user can reach"
}
2
{
$user = Read-Host "This feature only some user can reach and requires authentication. Entry your username to proceed"
$allowedUsers = "user1", "user2"
if($allowedUsers.contains($user))
{
write-output "This feature the user $user can reach. Please authenticate to continue"
if((UserAuthentication $user) -eq $true)
{
write-output "$user successfully authenticated"
}
else
{
write-output "$user unsuccessful authenticated"
}
}
else
{
write-output "This feature the user $user cannot reach"
}
}
}
function UserAuthentication($user)
{
return $true #May return 'True' if successfully authenticated or 'False' if not.
}
This answer is for when your users are member of an AD domain
I have changed the function name UserAuthentication to Get-Authentication to comply with the Verb-Noun function naming convention in PowerShell.
# helper function test if a username/password combination is valid.
# if valid, the username entered in the box is returned.
function Get-Authentication {
$Credentials = Get-Credential "$env:USERDOMAIN\$env:USERNAME" -Message "Please authenticate to continue" -ErrorAction SilentlyContinue
if ($Credentials) {
$UserName = $Credentials.UserName
$Password = $Credentials.GetNetworkCredential().Password # --> plain-text password
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$ds = New-Object System.DirectoryServices.AccountManagement.PrincipalContext Domain
if ($ds.ValidateCredentials($UserName, $Password)) {
# return the username entered
$UserName
}
}
}
# your code here
# fill in the SamAccountNames of allowed users for this feature
$allowedUsers = 'samaccountname','of', 'users', 'that', 'are', 'allowed', 'to', 'use', 'feature 2'
$feature = Read-Host 'Select the feature by typing the number [1 - 2]'
switch ($feature) {
'1' { Write-Output "This feature any user can reach" }
'2' {
$user = Get-Authentication
if ($null -ne $user -and $allowedUsers -contains $user) {
Write-Output "User $user is allowed for this feature"
}
else {
Write-Output "This feature the user cannot reach"
}
}
}
I am writing a powershell script to manage our local administrator accounts using a csv file.
#variable to store the data in data.csv
$userobjects = Import-CSV C:-data.csv
function main-list{
Write-Host "--------------------------------------"
Write-Host "Windows Powershell Account Manager"
Write-Host "--------------------------------------"
Write-Host "1 - Change Name"
Write-Host "2 - Disabled Account"
Write-Host "3 - Delete User"
Write-Host "4 - Exit"
[int]$action = Read-Host "Enter the menu number from above"
if ($action -eq 1){change-name}
if ($action -eq 2){disable-account}
if ($action -eq 3){delete-user}
if ($action -eq 4){cls; break}
}
function change-name
{
foreach ($user in $userobjects)
{
#Assign the content to variables
$FileHostname = $user.Host
$FileAccount = $user.Account
$FileNewname = $user.Rename
$FileDisable = $user.Disable
$FileDelete = $user.Delete
# Rename
if (($user.Account -ne $user.Rename) -and ($user.Rename -ne '' ))
{
#Write-Host "old name :"$FileHostname"/"$FileAccount "-> new name :"$FileHostname"/"$FileNewname
$connection = $FileHostname+"/"+$FileAccount
$accName = [ADSI]("WinNT://$connection")
if ($accName.path -eq "WinNT://"+$connection+"")
{
$accName.psbase.Rename($FileNewname)
Write-Host "Account(s) renamed"
$user.Account = $user.Rename
}
else
{
Write-Host "Account name :"$connection "can't be found on the host"
}
$user.Account = $user.Rename
$userobjects | export-csv C:-data.csv -notype
}
}
Write-Host "--------------------------------------"
main-list
}
function disable-account
{
foreach ($user in $userobjects)
{
#Assign the content to variables
$FileHostname = $user.Host
$FileAccount = $user.Account
$FileNewname = $user.Rename
$FileDisable = $user.Disable
$FileDelete = $user.Delete
if ($user.Disable -eq 'yes')
{
$connection = $FileHostname+"/"+$FileAccount
$accName = [ADSI]("WinNT://"+$connection+"")
if ($accName.UserFlags -eq '515')
{
Write-Host "Account :"$connection "is already disabled"
}
else
{
$accName.description = "Account disabled"
$accName.UserFlags = 2
$accName.setinfo()
Write-Host "Account(s) disabled"$connection
}
}
}
Write-Host "--------------------------------------"
main-list
}
function delete-user
{
foreach ($user in $userobjects)
{
#Assign the content to variables
$FileHostname = $user.Host
$FileAccount = $user.Account
$FileNewname = $user.Rename
$FileDisable = $user.Disable
$FileDelete = $user.Delete
#Delete
if ($user.Delete -eq 'yes')
{
$connection = $FileHostname+"/"+$FileAccount
$accName = [ADSI]("WinNT://"+$connection+"")
$accName.delete("user",$accName.name)
#Write-Host $connection deleted
}
else
{
Write-Host "Account name :"$connection "can't be found on the host"
}
}
}
}
$userobjects | export-csv C:-\data.csv -notype
main-list
I don't really know why I have this message when I am trying to use the delete function : "Unknown name", it is like it doesn't find the local account to delete it but I am not sure. However, It works perfectly when I want to rename or disable accounts.
My data file looks like that
http://www.noelshack.com/2016-05-1454622367-capture.png
I will post the real message when I will be back to work tomorow.
Thank you for your help.
Quick skim... wouldn't this need to be used instead? I think your $accName.name would be using the machine name.
$accName.delete("user",$user.account)
You delete() the user from the computer, so your [adsi] object should bind to the computer and call Delete() on that instead:
# Just the machine name, nothing more:
$Machine = [ADSI]"WinNT://$FileHostname"
# Now delete the user account from the machine
$Machine.Delete('user',$FileAccount)