Changing a variable based on output - powershell

Good Afternoon,
Just want to start by saying I am totally new with PS, and am really sorry if my approach to this is long winded or inaccurate.
I have a list of computernames that declared as individual Variables that my colleagues have provided me :
$Jon = "Abc1234"
$Mike = "Abc6789"
another 10 hostnames
I then ask the user if they want to send the files to another PC :
$Targetuser = Read-Host 'Who would you like to send it to?'
What I would like is the output from the above to change to the hostname, but I am unsure of how to do this.
Essentially, if the output was Mike, to change the $targetuser variable to $Abc6789
Thanks in advance

Dynamically named variables is almost always a bad idea. Instead, use a dictionary type, like a hashtable:
# Define user->host dictionary
$Hostnames = #{
Jon = "Abc1234"
Mike = "Abc6789"
}
# Ask user for target user
$TargetUser = Read-Host 'Who would you like to send it to?'
# Keep asking until the enter an actual user name
while(-not $Hostnames.ContainsKey($TargetUser)){
Write-Host "No hostname found for user '${targetUser}'!"
Write-Host "Choose one of:"
Write-Host ($Hostnames.Keys -join "`n")
$TargetUser = Read-Host 'Who would you like to send it to?'
}
# Get the associated hostname
$TargetHost = $Hostnames[$TargetUser]
# copy file to $TargetHost

Related

Powershell - Get partial name as Variable

First posting here, and I'm a beginner in Powershell (Or most script, in the matter of fact).
What a try to do here is to take a part of a name file, and use it later To download a file from our server with the same name.
$name = Get-childitem -Path "$env:USERPROFILE\AppData\Local\Microsoft\Outlook\*.ost" -name
$username = $name.Remove($name.IndexOf('#'))
Write-Output $Username
I only get the the file name without what I put between ${.}
Thanks for any help
Split the string on the # and grab only the first item from the resulting array:
$name = "FirstName.LastName#company.com - more text you don't care about.ost"
# String.Split() returns an array of strings, `[0]` gives us the first item in that array
$username = $name.Split('#')[0]
Alteratively, remove everything from the original string beginning at the first #:
$username = $name.Remove($name.IndexOf('#'))

How to look for members of a group or object with adsi

The company has an AD structure that I need to search for the groupnames where the user is member.
I do know it should be in the "memberof" attribute for the users, let's just say that is not always correct.
I tried the below code to find the username (or objectname) within the "members" attribute for all of the groups within an OU and then bring back the name of the group.
Unfortunately I think I am missing something.
Reverse search (IE: listing the members of a group) is working, but in my case I do not know the name of the groups. Also I need all of the groups, not just a single.
uname ="*anyoldusername*"
$Searcher = [ADSISearcher]"(member=$uname)"
$Searcher.SearchRoot = [ADSI] "LDAP://mydomainsearchroot"
$Searcher.PageSize = 10000
$result = $Searcher.FindAll().Properties.cn
echo $result
This should do it:
$UserName ="TestUser"
$Searcher = [ADSISearcher]""
$Searcher.SearchRoot = [ADSI]"LDAP://mydomainsearchroot"
$Searcher.Filter = "Name=$UserName"
$UserDN = $Searcher.FindOne().properties.distinguishedname
$Searcher.Filter = "(member:1.2.840.113556.1.4.1941:=$UserDN)"
$Searcher.PageSize = 10000
$result = $Searcher.FindAll().Properties.cn
$result
The first search is to find the DN of the user, since that's required for the filter in the next search. To read more about the "1.2.840.113556.1.4.1941" filter see this documentation.
Oh, and echo is an alias for Write-Output in Powershell, better to use that directly or even omit it entirely since a string or variable on it's own will default to Write-Output anyway as you can see when $result is run at the end.

Line break issue when configuring "send on behalf of"

I have a script to set send on behalf of permissions in Exchange Management Shell, but when you try and use it it fails because the output of the first part is too long and truncates over 2 lines.
First thing we do is build our array from lists of people and put them into some variables to pass:
function Add-Send ($mailbox, $target) {
#"Granting send on behalf for $mailbox to $target"
Set-Mailbox -Identity $mailbox -GrantSendOnBehalfTo #{ Add = $target }
}
We pass a long list as the $target and the maibox name is $mailbox and if we output the text we get:
Set-Mailbox -Identity "mr.jeff" -GrantSendOnBehalfTo #{ Add = "alan.alanson", "bob.bobson", "steve.stevenson" }
All fine and good but if there are more than N characters in the output then we get a line break:
Set-Mailbox -Identity "mr.jeff" -GrantSendOnBehalfTo #{ Add = "alan.alanson", "bob.bobson", "steve.stevenson", ...
..., "cath.cathdotir" }
When you run this script with the overlength output, then command fails as the output which should be passed to the CLI is passed over more than one line. PowerShell treats each line as a separate command, and they obviously fail with bad syntax.
Our string is output from an array that we build like this:
function Send-Array ($mailbox) {
$target = Get-Content ".\list\dpt1.txt"
$target += Get-Content ".\list\$mailbox.txt"
$target += Get-Content ".\list\dpt2.txt"
$target = $target | Select-Object -Unique
$separator = '", "'
$target= $target -replace '^|$','"' -join ','
Add-Send $mailbox $target
}
This gives us an array with strings that look like:
"alan.alanson", "bob.bobson", "steve.stevenson"
From here I am at a loss any ideas would be much appreciated.
The obvious solution would be to pass the names one at a time, but due to a gotcha with Exchange Server every time you set send on behalf of permissions with PowerShell it wipes the existing permissions, so you only end up with he last person granted permissions being able to send on behalf of.
See this link for help with your underlying issue.
Very basically, you will have to:
get the DistinguishedName of the user you need to add
store the current value of GrantSendOnBehalfTo in a variable
append the new user's distinguished name to the list
replace GrantSendOnBehalfTo with the new list
Afterwards you should not need to pass endless strings to the EMS (I hope so).

Is there a one-liner for using default values with Read-Host?

I've written something like this to specify default values for prompts.
$defaultValue = 'default'
$prompt = Read-Host "Press enter to accept the default [$($defaultValue)]"
if ($prompt -eq "") {} else {
$defaultValue = $prompt
}
Can it be shortened further?
Here is my attempt.
$defaultValue = 'default'
$prompt = Read-Host "Press enter to accept the default [$($defaultValue)]"
if (!$prompt -eq "") {$defaultValue = $prompt}
I want a one-liner, so I'm gonna hold out accepting an answer until then.
N.b. $defaultValue should be stored independently of the one liner. Similar to the example above.
I've accepted the answer which lead me to the solution I was looking for.
$defaultValue = 'default'
if (($result = Read-Host "Press enter to accept default value $defaultValue") -eq '') {$defaultValue} else {$result}
And for those of you asking why. The reason is because it is easier on the eyes of whoever comes after me. Less is always more, when clarity is not sacrificed. IMHO.
EDIT;
Instead of a single line, perhaps I should have said a single phrase?
I've added this edit clarify whilst a few answers I have seen use are using a semi-colon.
$defaultValue = 'default'
$prompt = Read-Host "Press enter to accept the default [$($defaultValue)]"
$prompt = ($defaultValue,$prompt)[[bool]$prompt]
If you absolutely have to have it in one line:
$defaultValue = 'default'
($defaultValue,(Read-Host "Press enter to accept the default [$($defaultValue)]")) -match '\S' |% {$prompt = $_}
Shortest Version I could came up with:
if (!($value = Read-Host "Value [$default]")) { $value = $default }
This version doesn't have to use else.
if(($result = Read-Host "Press enter to accept default value [default]") -eq ''){"default"}else{$result}
$DefaultValue="Foobar"
.... (Optional other code) ....
$Value=if($Value=(Read-Host "Enter value [$DefaultValue]")){$Value}else{$DefaultValue}
Just threw this together to re-use a previously entered config value while still allowing user to change it if needed... The accepted answer is missing the assignment portion and uses a hardcoded "Default" value...
There is a function (from other languages) called "Ternary Operator" or "Binary Operator"(https://en.wikipedia.org/wiki/%3F:) (the 'xx : yy ? zz' style one) and there are several people who have submitted functions to implement its behavior in Powershell.
For me this is the shortest, easiest to use, and doesn't repeat the variable value or name:
$ChosenValue = 'Default Value' | %{ If($Entry = Read-Host "Enter a value ($_)"){$Entry} Else {$_} }
The magic sauce is the |%{} that pipes the default value to ForEach, allowing repeating the default value (aliased as $_) in the message and return value. It also depends on the fact that the assignment operator returns the value assigned for the purposes of the If statement. This assigned value will be treated as $true when an entry is provided, or $false(empty) when the [Enter] key is pressed instead.
Thanks go to #ojk's excellent answer which I considered the easiest to use and read, but I agree with #bluekeys that it's better to avoid repeating the default value and assigned variable name. Having the intermediate $Entry variable hasn't proven to be an inconvenience.
I use this method frequently to define function or script parameters with defaults that can be overridden at run time:
param(
$hostname = ('google.com' | %{ If($Entry = Read-Host "Host name ($_)"){$Entry} Else {$_} })
)
Write-Host $hostname
Running:
Host name (google.com):
google.com
Host name (google.com): facebook.com
facebook.com
Also, as #E.Sundin pointed out, Powershell 7 finally has a ternary operator that makes this syntax much simpler. Unfortunately many of us work on legacy systems that won't get version 7 in the near future.
EDIT: here's a slightly shorter version without an intermediate $Entry variable:
$hostname = 'google.com' | %{(Read-Host "Host name ($_)"),$_} | ?{$_} | Select -First 1
It makes an array containing the Read-Host response and the default value, then filters to exclude empty values, and selects the first (there would be two if the user responded).
$prompt = ( ($defaultValue='a_default_value'), (Read-Host "Please enter something [$defaultValue]")) -match '\S' | select -last 1
The given answers doesn't satisfy me (and don't work for me) but gave me enough input to came up with the shortest one-liner.
if (($prompt = Read-Host -Prompt "Your Text [your default]") -eq "") {$prompt= "your default"}
Why adding an else? If user inputs nothing it does $prompt="your default" (could be a variable of course). If he adds something, its stored in %prompt already and you can leave the statement.
I am using a function for that:
Function Read-HostDefault($Prompt, $Default) {
if ($default) {
$prompt = "$prompt [$default]"
}
$val = Read-Host $prompt
($default,$val)[[bool]$val]
}
Which gives:
PS C:\Windows\system32> Read-HostDefault "Enter port" 5432
Enter port [5432] :
5432
PS C:\Windows\system32> Read-HostDefault "Enter port" 5432
Enter port [5432] : 1234
1234
PS C:\Windows\system32> Read-HostDefault "Enter port"
Enter port : 2468
2468
You could also use a switch statement in a single line like this:
param([string]$myVariable = $($($val = $(Read-Host "Enter value")); $(Switch -regex ($val) { ".+" { $val } default { "my default value" } })))
The -regex .+ will match one or more characters, this would include any white space characters so maybe you want to strip out white space when doing the switch match i.e. \S.+.
Assuming you already have $defaultValue:
$newValue = if ($value = Read-Host -Prompt "Please enter a value ($defaultValue)") { $value } else { $defaultValue }
This should work

create var from .exe output in powershell

I need to make a variable from the ID number of a username
qwinsta.exe /server:vm041 derpy.herp
This returns the following output
SESSIONNAME USERNAME ID STATE TYPE DEVICE
derpy.herp 3 Disc
I need to create a variable in powershell with a value of 3 as per output above.
This code will be used to look through a number of servers to see if an individual user is logged in and disconnect them with rwinsta.exe
Here's quite a crude regular expression - I don't know qwinsta.exe so I'm not sure of the permutations of data it can return - this works with your above example though.
This will assign 3 to the variable $ID.
$output = qwinsta.exe /server:vm041 derpy.herp
$output -match ".*derpy.herp.*(\d).*"
$ID = $Matches[1]
you may be able to parameterise the username like so:
$username = "derpy.herp"
$output = qwinsta.exe /server:vm041 $username
$output -match ".*$username.*(\d).*"
$ID = $Matches[1]
HTH,
Matt
You can parse the output you are obtaining, get your ID, and then use New-Variable cmdlet to instance your variable.