Is it possible to use variable nested command splatting - powershell

I am just wanting to check if it is possible to use If statements to set the value of a nested command splat in PowerShell. Below is what I have currently:
$SADUParams = #{
Identity = $SAM
Company = $Company
Server = $ADserver
Replace = #{"extensionattribute11"="$Department";"extensionattribute12"="RESOURCE"}
}
if($PhoneNo){
$SADUParams["OfficePhone"] = $PhoneNo
}
Set-ADUser #SADUParams
What I would like to also do is update ExtensionAttribute12 using an if statement like with the phone number in the example above.
Is this possible, and if so, how do I code it?

Sure, just simple access the desired property from the $SADUParams hashtable and update it:
if ($true <#yourcondition#>)
{
$SADUParams.Replace.extensionattribute12 = "your_new_value"
}

Related

How to access properties in a nested hashtable without explicitly stating the property names?

Let's say I have a 2-level nested hashtable like this:
$programs = #{
program1 = #{
DisplayName = "DisplayName1"
Program = "C:\program1.exe"
}
program2 = #{
DisplayName = "DisplayName2"
Program = "C:\program2.exe"
}
}
now, without explicitly mentioning each of the property names like this:
$programs.program1['program']
I want to iterate over the hashtable like this:
foreach ($Name in $programs) {
$r = Get-NetFirewallRule -DisplayName $programs.Keys['DisplayName'] 2> $null;
if (-NOT $r) {
New-NetFirewallRule -DisplayName $programs.Keys['DisplayName'] -Program $program.Keys['Program']
}
}
but I keep getting errors like:
Cannot validate argument on parameter 'DisplayName'. The argument is null. Provide a valid value for the argument, and then try running the command again.
InvalidOperation: untitled:Untitled-2:29:13
what am I doing wrong?
what is the right way to access nested hashtable properties like this without explicitly mentioning their names? I want to know the synatx of it so that if I ever have a 3 or 4 level nested hashtables I can access them without specifying their exact names.
even if we ignore the foreach loop, how to only list all the "DisplayName" properties? what if the "DisplayName" properties were in a 4-level nested hashtable and we wanted to list them in the PowerShell console without specifying the exact names of the items that came before it?
Thanks to the comments from Santiago Squarzon and zett42, here is the syntax to access properties of deeply nested hashtables.
$programs.Values.Values.Values and so on.
I found it work perfectly.
also, after reading foreach and as mentioned in the comments, I found that my code above was incorrect and the correct way is this:
foreach ($Name in $programs.values.GetEnumerator()) {
$r = Get-NetFirewallRule -DisplayName $Name.DisplayName 2> $null;
if (-NOT $r) {
New-NetFirewallRule -DisplayName $Name.DisplayName -Program $Name.Program
}
}
in a foreach loop, we have to use the variable we create in the parenthesis. my mistake was that I was using the collection itself again.

powershell hashtable dynamic key

I would like to ask you about dynamic nested keys in hashtables (powershell).
I 've already done some research and I can't find an answer.
# I got this hash structure, works fine
$Hashtable = #{}
$Hashtable.Maincategory = #{}
$Hashtable.Maincategory.Subcategory = #{}
$Hashtable.Maincategory.Subcategory.MyProperty = #{ 'property' = 'value'}
$Hashtable.Maincategory.Subcategory.MyProperty
Name Value
---- -----
property value
# I want dynamic path to my property
$MainAndSubCategory = [string]'Maincategory.Subcategory'
$Hashtable.$MainAndSubCategory.MyProperty # doesn't work
$Hashtable."$MainAndSubCategory".MyProperty # doesn't work
$Hashtable."$($MainAndSubCategory)".MyProperty # doesn't work
$Hashtable."$(Get-Variable -Name 'MainAndSubCategory' -ValueOnly)".MyProperty # doesn't work
I would appreciate advice, thanks in advance.
It is possible to build a string, then execute it using Invoke-Expression. Note that the initial $ character is escaped.
$Hashtable = #{}
$Hashtable.Maincategory = #{}
$Hashtable.Maincategory.Subcategory = #{}
$Hashtable.Maincategory.Subcategory.MyProperty = #{ 'property' = 'value'}
$Hashtable.Maincategory.Subcategory.MyProperty
$MainAndSubCategory = 'Maincategory.Subcategory'
Invoke-Expression -Command "`$Hashtable.$MainAndSubCategory.MyProperty"
One thing to be careful about is that anything that could set the value of the string would be able to inject unwanted code.
this will work, but I'm not sure, if this is a solution, you are looking for
$Hashtable.$(($MainAndSubcategory -split '\.')[0]).$(($MainAndSubcategory -split '\.')[1]).myproperty
It is the same as put maincategory and subcategory keys into the separate variables

Set-ADuser extensionAttribute won't work but things like title will

I am writing a simple script that takes an already created user and updates an attribute based on what the admin put in.
The code works just fine if I replace extensionAttribute with for example title or something like that, but it won't with extensionAttributes.
I have tried a few things and other extensionAttributes but the code is so simple and it works with other Attributes. I am guess extensionAttributes require a bit more in the code that I am missing.
$name = Read-Host "AD Logon Name"
$key = Read-Host "Azure Key"
Set-ADUser $name -extensionAttribute6 $key -PassThru
Set-ADUser : A parameter cannot be found that matches parameter name 'extensionAttribute6'
Even though it exists it is not finding it.
Set-ADUser has a limited set of parameters covering the most commonly used attributes in AD. However, given the sheer amount of existing attributes and the fact that the AD schema is extensible, an attempt to have all attributes represented as parameters just wouldn't be feasible.
For attributes that are not represented as parameters use the parameter -Add or -Replace with a hashtable argument.
Set-ADUser $name -Replace #{'extensionAttribute6' = $key} -PassThru
Old thread, but this worked for me:
Import-Csv -Path "C:\data\12345.csv" |ForEach-Object {
Set-ADUser $_.samAccountName -replace #{
description = "$($_.description)"
extensionAttribute1 = "$($_.extensionAttribute1)"
extensionAttribute3 = "$($_.extensionAttribute3)"
initials = "$($_.initials)";
#additionalAttributeName = "$($_.additionalAttributeName)"
#additionalAttributeName = "$($_.additionalAttributeName)"
#additionalAttributeName = "$($_.additionalAttributeName)"
#additionalAttributeName = "$($_.additionalAttributeName)"
#additionalAttributeName = "$($_.additionalAttributeName)"
}
}
The top row of your .csv file would look like the following for this example:
samAccountname,description,extensionAttribute1,extensionAttribute3,initials

How to get Database Name from Connectionstring in PowerShell

I'm trying to get the Database name from a connection string in PowerShell.
"Server=server\instance;uid=User;pwd=Hello;Database=SomeName;"
I can think of two ways to do that, either to search for the string Database, up until the first ; after that split the string on = and select the Databasename - but I don't really know how to do that.
The second way could be with the DBConnectionStringBuilder like this:
$sb = New-Object System.Data.Common.DbConnectionStringBuilder
$sb.set_ConnectionString($cstring)
[string]$Database = ($sb | ? {$_.Keys -eq 'Database'}).value
but with this way, no matter how hard i try to filter the Databasename, it won't give me the databasename returned.
Question: What's the best way to get my Databasename from the connection string?
Use the second method, but simplify it:
$cstring = "Server=server\instance;uid=User;pwd=Hello;Database=SomeName;"
$sb = New-Object System.Data.Common.DbConnectionStringBuilder
$sb.set_ConnectionString($cstring)
$Database = $sb.database
This works perfectly fine.
If you want to avoid an error in the case where the key doesn't exist, there are a lot of ways to do that, the more idiomatic method of looking for the key first:
if ($sb.HasKey('Database')) {
$Database = $sb.Database
}
Or the object's own TryGetValue method:
if ($sb.TryGetValue('Database', [ref] $Database)) {
# It was successful
# $Database already contains the value, you can use it.
} else {
# The key didn't exist.
}
String Parsing
I don't recommend these in this case because there is some flexibility in the database connection string format, and why make your code aware of all the possibilities and try to correctly handle them all when that code was already written (the object you're using above)?
But for completeness, I'd do it with splitting and regular expression matching and capturing:
$cstring -split '\s*;\s*' |
ForEach-Object -Process {
if ($_ -imatch '^Database=(?<dbname>.+)$') {
$Database = $Matches.dbname
}
}
So here I'm first splitting on a semi-colon ; surrounded by any amount of whitespace. Each element (which should be just key-value pairs) is then checked against another regex, looking specifically for Database= and then capturing what comes after that until the end of the string, in a named capture group called dbname. If the match is successful, then the result of the capture group is assigned to the variable.
I still prefer a proper parser when one exists.
try this
"Server=server\instance;uid=User;pwd=Hello;Database=SomeName;".split(";") |
%{[pscustomobject]#{Property=$_.Split("=")[0];Value=$_.Split("=")[1]}} |
where Property -eq "Database" | select Value
other solution
$template=#"
{Property*:Abc123}={Value:Test123}
{Property*:Def}={Value:XX}
"#
"Server=server\instance;uid=User;pwd=Hello;Database=SomeName;".replace(";", "`r`n") | ConvertFrom-String -TemplateContent $template |
where Property -eq "Database" | select Value

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.