Writing a hashtable value to an attribute - powershell

Powershell newbie here, my first script.
I have user objects with an AD custom attribute named tvCode with a values of 123456 or 6787682 or 983736 etc.
I would like to script something that will get the tvCode value from the user object
When:
123456 = Sony
6787682 = Samsung
9837343 = LG
Write the value of "Sony" or "Samsung" or "LG" to the "City" attribute of the user object.
Looks like i may need to use a hashtable.
If possible do this for a specific OU
hope this makes sense
thanks

function Convert-TVCode {
Param
(
[parameter(Mandatory=$true,Position=0,ValueFromPipeline=$true)]
[String[]]
$Code
)
Process {
foreach ($C in $Code) {
switch ($C) {
"123456" {$brand = "Sony"}
"6787682" {$brand = "Samsung"}
"9837343" {$brand = "LG"}
default {
$brand = $null
Write-Warning "$C not included in switch statement. Returning"
return
}
}
if ($brand) {
Write-Verbose "Code '$C' matched to Brand '$brand' -- searching for users to update"
Get-ADUser -Filter "tvCode -eq '$C'" | Set-ADUser -Replace #{tvCode=$brand}
}
}
}
}
This function will allow you to update any users that have their tvCode attribute set as one of the target numerical values. You can have it hit multiple codes at once as well.
Examples:
Convert-TVCode -Code 123456
Convert-TVCode -Code 123456,6787682
Convert-TVCode -Code 123456,6787682,9837343 -Verbose
Update the switch statement in the function to customize it to your actual values and let me know if you have any questions!

Related

How to get creation date in sitecore with powershell

I wrote a script in order to replace the "$date" in release date of many Sitecore items with their creation date (created).
I have a problem to get this field from Sitecore.
I tried this:
$rootItem = Get-Item master:/content
$sourceTemplate = Get-Item "/sitecore/content/.../item 1"
foreach($field in $sourceTemplate.Fields) {
if (($field -ne $null) -And ($field -like '$date')) {
$sourceTemplate.Editing.BeginEdit()
$CreatedDate = .......
$field.Value = [sitecore.dateutil]::ToIsoDate($CreatedDate)
$sourceTemplate.Editing.EndEdit()
}
}
I also tried to get this field by ID but it doesn't work.
Does someone have an idea please?
Thank you
If you want to check Sitecore built-in fields, you need to call $sourceTemplate.Fields.ReadAll(); first.
You should compare value of the field with $date string, not the field itself.
Then just get the string which is stored in the __Created field instead of getting date and then formatting it back to ISO date string.
And the last thing - don't call Editing.BeginEdit() and Editing.EndEdit() mutliple times for the same item - Sitecore runs some havily operations when it's called so make sure you only call it once per every item which needs it.
$sourceTemplate = Get-Item "/sitecore/content/home/test"
$sourceTemplate.Fields.ReadAll();
$editing = $false
foreach($field in $sourceTemplate.Fields) {
if ($field.Value -eq '$date') {
if (!$editing) {
$editing = $true
$sourceTemplate.Editing.BeginEdit();
}
$field.Value = $sourceTemplate.Fields["__Created"].Value
}
}
if ($editing) {
$edited = $sourceTemplate.Editing.EndEdit();
}

Getting a FieldLookupValue from Sharepoint in Powershell

Looking on the net I came up with this 2 functions to request Sharepoint using this 3 DLL with powershell :
Microsoft.SharePoint.Client.dll
Microsoft.SharePoint.Client.Taxonomy.dll
Microsoft.SharePoint.Client.Runtime.dll
This function is used to get all items from a list
Function Get-ListItems([Microsoft.SharePoint.Client.ClientContext]$Context, [String]$ListTitle) {
$list = $Context.Web.Lists.GetByTitle($listTitle)
$qry = [Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery()
$items = $list.GetItems($qry)
$Context.Load($items)
$Context.ExecuteQuery()
return $items
}
And this one to work the list :
Function getChangeListsFromSharepoint(){
$context = New-Object Microsoft.SharePoint.Client.ClientContext($Url)
$items = Get-ListItems -Context $context -ListTitle $listName
foreach($item in $items)
{
/** Working HERE **/
}
$context.Dispose()
}
Now when I'm displaying all item content using Write-Host $item.Fields I've got something like this :
[Title,"blabla"]
...
[SpecialField,Microsoft.SharePoint.Client.FieldLookupValue[]]
[OtherField,Microsoft.SharePoint.Client.FieldLookupValue]
I'm trying to get the value of SpecialField and OtherField. To do so I'm using $item["SpecialField"].LookupValue. And I've got no problem. But when I'm doing it on OtherField the value is empty. If I try to use $item["OtherField"].LookupID the value is not empty and I've got an ID. How can I get the value behind this ID ? What's the difference between FieldLookupValue[] and FieldLookupValue ?
FieldLookupValue[] is a multi-value lookup column.
It has property Allow multiple values set to true and contains an array of items.
So, $item["OtherField"].LookupValue will not work here, you need to iterate it over as below:
#multi-value lookup
$mvLookup = [Microsoft.SharePoint.Client.FieldLookupValue[]] $item["OtherField"]
$mvLookup |% { "Lookup Value: $($_.LookupId):$($_.LookupValue)" }
which results in values as below:
FieldLookupValue is a single value lookup column. It has the Allow multiple values set to false and contains a single item. So, $item["SpecialField"].LookupValue will work here
So the solution was easy : my user didn't had the rights to explore the (field)list because it was from a (sharepoint)list on wich he didn't had any rights. What is strange is that on the website the value was visible but it's not when using powershell.

Comparing AD sites and SCCM boundaries

I m trying to compare the Active directory sites with SCCM boundaries, by using the below powershell scripts, but its not giving the output as expected.
There are 3 AD sites actually available in SCCM, however the script gives me an output that there is no AD sites available in SCCM boundaries.
$sites = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest().Sites
$CMBoundary = Get-CMBoundary | select value
foreach ($adsite in $sites.name) {
foreach ($cmb in $CMBoundary.value ) {
if (($cmb | select value) -eq ($adsite | select name)) {
"$adsite available in CM"
}
else { "$adsite is NOT in CM $cmb" }
}
}
Could someone please help me on this.
Think I see the issue.
On line 3, you're selecting the .Name property from $sites and storing it in $adsite, for each step of your loop.
foreach ($adsite in $sites.name) {
However, you then also attempt to take the .Name property again, with this line:
if (($cmb | select value) -eq ($adsite | select name))
This won't work. You've set $adsite to be equal to whatever was in $sites.Name, but that doesn't give a .Name property to $adsite.
Try this again, this time with the second Select statement removed. The reason this was failing is that there wouldn't be anything to compare against. I've revised your code to remove this logic, let me know if it works.
foreach ($adsite in $sites.name) {
foreach ($cmb in $CMBoundary.value ) {
if ($cmb -eq $adsite) {
"$adsite available in CM"
}
else { "$adsite is NOT in CM $cmb" }
}
}
Be warned, however, that if your boundary name doesn't exactly match an AD Site name, that this code will give you a lot of false positives.

How to check to see if what went through the hashtable matched anything

I have a hashtable and I'm trying to make an if statement right now that will check to see if what went through the hashtable matched anything within it.
$netVerConv = #{
'v2.0' = "lib\net20";
'v3.0' = "lib\net30";
'v3.5' = "lib\net35";
'v4.0' = "lib\net40";
'v4.5' = "lib\net45";
}
$target = $netVerConv.Get_Item($netVerShort)
if () {
}
Above is the area of my code I'm working with, the target variable runs $netVerShort through the $netVerConv hashtable using a Get_Item command. The if statement that I've laid the framework for would check to see if netVerShort matched anything within the hashtable and if it didn't it will stop the program, which I know how to do with a simple exit command.
The other suggestions will work in your specific scenario but in general you should use the ContainsKey() method to see if a key exists in the hashtable. For instance the hashtable value could be $null or $false in which case, testing via the result of Get_Item() or more simply Item[$netVerShort], will return a false negative. So I recommend this approach for testing existence of a key in a hashtable. It is also more obvious what your intent is:
if (!$netVerConv.ContainsKey($netVerShort) {
...
}
How about this:
if( $target -eq $null ) {
echo "Didn't Match"
exit
}
Another option:
if (-not ($target = $netVerConv.Get_Item($netVerShort)))
{
Write-Error "Version $netVerShort not found"
Exit
}
You could also re-factor that as a Switch
$target =
Switch ($netVerShort)
{
'v2.0' {"lib\net20"}
'v3.0' {"lib\net30"}
'v3.5' {"lib\net35"}
'v4.0' {"lib\net40"}
'v4.5' {"lib\net45"}
Default {
Write-Error "Version $netVerShort not found"
Exit
}
}

Powershell - Array Range from user input

What would be the easiest way to get user input for an array range.
For example:
function MyArrayOfMachines {
[CmdletBinding()]
param(
[parameter(Mandatory=$true)][string]$Machine
# What should I assign the $Range variable as?
)
# Hardcoded range. User should be able to enter the range
$Range = 2..5
for ($i=0; $i -lt $array.length; $i +=1)
{
$result = $array[$i]
$output = $machine+$result
$output
}
}
The above function should take the input as the name of the machine and the array range. For now I have the array range hardcoded. When I assign $Range as [Array]$Range in the user prompt, there is a prompt for $Range[0] etc etc. But I would like the user the enter the range.
Doesn't this work? Unless I misunderstood your question...
function test($range){
$range
}
test -range (1..5)
You can also accept the range as a string and parse it yourself:
function Test
{
param($range)
if($range -is [String])
{
[int]$start, [int]$end = $range.split('.', [StringSplitOptions]::RemoveEmptyEntries)
$start..$end
}
else
{
$range
}
}
The reason for the if / else is for cases where the user passes an actual range, as in manojlds answer, rather than a string to be parsed (like 1..5). This means you can't strongly type the param though.
Make it two parameters:
function test{
param ( [int]$st,
[int]$end)
$Range = $st..$end
$Range
}
test 1 5
If they input the start and end of the range you can use that to create it dynamically in the function.
EDIT:
To get the range from a string, try:
function test{
param ($Range)
$NewRange = $Range.substring(0,($Range.indexof('.')))..$Range.substring(($Range.lastindexof('.') + 1))
$NewRange
}
test 1..5
I agree with #manojlds, the range should be passed in as an array. Parsing a string limits the possibilities of what a user could enter. By using [int[]] you can force the user to specify an array of integers. This would also allow a user to specify a broken range such as ((2..4)+(6..12)) which is harder to allow for when parsing strings.
In your example I'm not sure where $array is coming from, and you only need one line to return a computed machine name.
function MyArrayOfMachines {
param(
[parameter(mandatory=$true)]
[string] $machine,
[parameter(mandatory=$true)]
[int[]] $range
)
foreach($n in $range) {
$machine+$n
}
}
You could create a single machine name,
MyArrayOfMachines Laptop 1
a range of machines,
MyArrayOfMachines Workstation (2..10)
or a non-consecutive array of machines
MyArrayOfMachines Server ((2..3)+(5..9))
You could just pass a string and evaluate it:
function Test([string]$range) {
if ($Range -match '^\d+\.\.\d+$') {
$RangeArray = Invoke-Expression $Range
} else {
$RangeArray = 1..5
}
}
Some minimal validation is done to ensure that the user cannot pass arbitrary code.