PowerShell Active Directory list all Multi-Valued attributes - powershell

not sure if I'm chaing the wild goose here but as per subject I'd need to get a list of AD attributes, for the user ObjectClass, that are multie valued.
For example the proxyAddresses exchange specific attribute is multi valued where extensionAttribute* only accept a single string.
We use a heavily customized schema and while I could go through each attribute documentation I'd rather get a list of aforementioned attributes via PowerShell.
I've tried using ldp.exe but could not achive desired results and was wondering if there is a way to do this via PowerShell or .Net managed code.
Thanks in advance for any help/pointer.

So you have to query the Schema part of the directory and look for objectClass attributeSchema and attribute isSingleValued (FALSE). The part of the distinguichName wichh is invariant is : CN=Schema,CN=Configuration.
try first with CSV :
csvde -f MultivaluedAttributes.csv -d CN=Schema,CN=Configuration,DC=MySubdomain,DC=MyDomain,DC=com -r "(&(objectclass=attributeSchema)(isSingleValued=FALSE))" -l lDAPDisplayName
Here is the powershell code.
# LDAPSchemaQuery.PS1
try
{
$dn = New-Object System.DirectoryServices.DirectoryEntry ("LDAP://179.22.21.01/CN=Schema,CN=Configuration,DC=MyDomain,DC=MyExt","MyUser", 'MyPassword')
# Query into the Schema
# csvde -f MultivaluedAttributes.csv -d CN=Schema,CN=Configuration,DC=office,DC=coyotesystems,DC=com -r "(&(objectclass=attributeSchema)(isSingleValued=FALSE))" -l lDAPDisplayName
$Rech = new-object System.DirectoryServices.DirectorySearcher($dn)
#$Rech.filter = "(&(objectclass=user)(mail=*)(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))"
$Rech.filter = "(&(objectclass=attributeSchema)(isSingleValued=FALSE))"
$Rech.SearchScope = "subtree"
$dumy=$Rech.PropertiesToLoad.Add("lDAPDisplayName")
$adAttributes = $Rech.findall()
foreach ($adAttribute in $adAttributes)
{
$multivaluedAttribute = try{$adAttribute.Properties["lDAPDisplayName"]}catch{""}
$multivaluedAttribute
}
}
catch
{
Write-Verbose "LDAPSchemaQuery : PB with $($adAttribute.Path)"
}

Related

Powershell query multidimensional hash

I'm struggling creating and querying data of an object. (I think hash table)
two environment (test and production)
two servertypes per environment (webserver and appl servers)
1 or more servers of each type
I want to store the hostnames within the applicable section. I created the following hash:
$arr =#{}
$arr.Environment = #{}
$arr.Environment.Production = #{}
$arr.Environment.Production.serverType = #{}
$arr.Environment.Production.serverType.webServer = #{}
$arr.Environment.Production.serverType.entServer = #{}
$arr.Environment.Test = #{}
$arr.Environment.Test.serverType = #{}
$arr.Environment.Test.serverType.webServer = #{}
$arr.Environment.Test.serverType.entServer = #{}
I found that I can access data like:
$serversArray.Environment.Test.serverType.webServer
I would like to know:
is this the right way of doing this? are there better / easier way to accomplish this?
how do I loop/filter this object, retrieving servernames that meet the specified criteria? Since I need to have 1. all test webservers then 2. all test appl servers etc
thanks
If you're able to save all this in one go (using variables or hardcoded strings), you should be using the native format to store it - much more readable.
See
$Optiplex = #{
'Brand' = 'Dell'
'Model' = 'Optiplex'
'Specs' = #{
'RAM' = '4 GB'
'CPU' = 'Intel i5'
'USB Ports' = '3'
'CD/DVD Drive' = 'No'
'HDD' = '320 GB - SSD'
} #Specs
} #Optiplex
From this walkthrough
You'll be able to access the variables for the hashtable in the same way, such as Optiplex.Specs.RAM to get the value for RAM.
Edit: To better answer question number 2, here's some idea on looping:
foreach ($serverTypeToKVs in $arr.Environment.Production.serverType.GetEnumerator()) {
Write-Host "ServerType $(serverTypeToKVs.Name):"
foreach ($keyVal in $serverTypeToKVs.Value.GetEnumerator()) {
# Logic if serverTypeToKVs.Name == "webServer"
# Logic if keyVal == something
# General work to be done
}
}
I found following way to achieve this:
$order = #(("Test","Production"),("webServer", "entServer"))
foreach($env in $order[0]) {
Write-Host "Environment: $env"
foreach($svr in $order[1]) {
Write-Host "ServerType: $svr"
write-host "hostnames: "$serversArray.Environment.$($env).serverType.$($svr)
}
}
This will loop the correct way/sequence and lists correct servers:
Environment: Test
ServerType: webServer
hostnames: tweb1 tweb2
ServerType: appServer
hostnames: tapp1
Environment: Production
ServerType: webServer
hostnames: pweb1 pweb2 pweb3
ServerType: appServer
hostnames: papp1 papp2 papp3 papp4

Parse data using Powershell and convert to Json

Background.
i have IBM CDC Replication engine and i need to check subscriptions status by using Zabbix.
Im calling subs status by cmd.exe /C "C:\Program Files\IBM\InfoSphere Data Replication\Management Console\bin\chcclp.exe" -f c:\CDC_Check.txt where CDC_Check.txt is script for that chcclp CLI
//Check the status of all subscriptions
//Source datastore: ***
//Target datastore: ***
chcclp session set to cdc;
// Turn on verbose output.
set verbose;
// Setting variables.
set variable name "ACCESS_HOSTNAME" value "";
set variable name "ACCESS_PORT" value "";
set variable name "ACCESS_USERNAME" value "";
set variable name "ACCESS_PASSWORD" value "";
set variable name "SOURCE_DATASTORE" value "";
set variable name "TARGET_DATASTORE" value "";
// Connecting to Access Server.
connect server
hostname "%ACCESS_HOSTNAME%"
port "%ACCESS_PORT%"
username "%ACCESS_USERNAME%"
password "%ACCESS_PASSWORD%";
// Connecting to the source and target datastores.
connect datastore name "%SOURCE_DATASTORE%";
connect datastore name "%TARGET_DATASTORE%";
// Setting the datastore context.
select datastore name "%SOURCE_DATASTORE%" context source;
select datastore name "%TARGET_DATASTORE%" context target;
// List replication state and latency of all subscriptions.
monitor replication;
// Disconnecting from datastores and Access Server.
disconnect datastore name "%SOURCE_DATASTORE%";
disconnect datastore name "%TARGET_DATASTORE%";
// Disconnect from Access Server and terminate the script.
disconnect server;
exit;
and im receiving following result:
Im trying to parse Subscription + Status and move it to Json for next integration with zabbix.
Im very new in PS so i still have no normal progress.
I understand idea that i need to capture anything that going under SUBSCRIPTIONS and STATE and write it to Json.
The first step would be to redirect the output of the app so you can read it in for parsing.
cmd.exe /C "C:\Program Files\IBM\InfoSphere Data Replication\Management Console\bin\chcclp.exe" -f c:\CDC_Check.txt > C:\temp\file.log
Then you can use the get Get-Content cmdlet to get it in your console session
$fileContent = Get-Content -Path "C:\temp\file.log"
Once it's in an array you can parse it like so.
$i=0
$fileContent | %{
$i++
if($_ | Select-String -Pattern "SUBSCRIPTION STATE" -CaseSensitive){
$headerIndex = $i
}
}
$headerIndex += 2 #start of report data to capture
This loop continues until it finds the blank line in the output
$hashObj= #{}
for ($x = $headerIndex; $fileContent[$x].length -gt 1 ;$x++){
$hashObj.Add("$($fileContent[$x].Substring(0,19).Trim(' '))","$($fileContent[$x].Substring(20,19).Trim(' '))")
}
#converts your hashtable to json object
$jsonObj = $hashObj | convertto-json
Not entirely sure how you need the json formatted but this will be what to expect your output to be similar to
{
"S_ACC_D": "Mirror Continuous",
"S_ACC_E": "Mirror Continuous",
"S_ACC_A": "Mirror Continuous",
"S_ACC_B": "Mirror Continuous",
"S_ACC_C": "Mirror Continuous"
}

How to remove a permission, a member, or a role?

I have this script below to add roles and members and permissions
Import-Module sqlserver
$Server = new-Object Microsoft.AnalysisServices.Tabular.Server
$Server.Connect("SERVER\INSTANCE")
$TabDB = $SERVER.Databases["DATABASENAME"]
$AddRole = new-Object Microsoft.AnalysisServices.Tabular.ModelRole
$AddRole.Name = 'NewRole1'
$AddRole.ModelPermission="Read"
$RoleMember = New-Object Microsoft.AnalysisServices.Tabular.WindowsModelRoleMember
$RoleMember.MemberName = 'DOMAIN\ACCOUNT'
$TabDB.Model.Roles.Add($AddRole)
$AddRole.Members.Add($RoleMember)
$TabDB.Update([Microsoft.AnalysisServices.UpdateOptions]::ExpandFull)
$server.Disconnect()
How can I remove a permission, a member, and a role?
I tried this at least for the role, but the console returns back "False"
$TabDB.Model.Roles.Remove($AddRole)
When working with ssas from powershell (or C# for that matter) you can use the analysisservices namespace of microsoft:
Microsoft analysisservices.
This is an object oriented way of working with ssas databases.
This is an old script I wrote for maintainers:
function addRoleToDb {
$roleName = Read-Host "How should this role be called?"
if ($global:dataBase.Roles.findByName($roleName)) {
echo "This role already exists"
return
} elseif ($roleName -eq "") {
echo "You can't give an empty name for a role."
return
}
echo "Warning: this role will start out empty and will have to be modified in order to be used. (it wil have read permission)"
[Microsoft.AnalysisServices.Role] $newRole = New-Object([Microsoft.AnalysisServices.Role])($roleName)
$global:dataBase.Roles.add($newRole)
$dbperm = $global:dataBase.DatabasePermissions.add($newRole.ID)
$dbperm.Read = [Microsoft.AnalysisServices.ReadAccess]::Allowed
$global:dataBase.Roles.Update()
$dbperm.Update()
return
}
At this point I already had a global variable database.
This is a method that would add a role to the database. Deleting the database would work practically the same, you would get the instance of the role with:
role = database.roles.findbyname()
or
role = database.roles.findbyid()
and then
role.Drop(DropOptions.AlterOrDeleteDependents);
You should check that last line before using it because the alterordeletedependants is something I now use in my c# program, I don't remember if it worked in powershell.
Good luck!

How do I retrieve PR_RULE_ACTIONS via PowerShell and the EWS Managed API?

I have need of retrieving and inspecting the delegate forwarding rule (the built-in delegate commands in EWS being inadequate for my needs since they choke on groups being used as delegates).
I am able to successfully locate the rule created by "Schedule+ EMS Interface". However, I am unable to retrieve PR_RULE_ACTIONS. Turning on tracing.
I see that the PidTagRuleMsgProvider property is getting returned just fine, but PR_RULE_ACTIONS never does.
I suspect that I am using the wrong MAPI property type in the propertyset definition, but I've gone through everything listed at http://msdn.microsoft.com/en-us/library/exchangewebservices.mapipropertytypetype(v=exchg.140).aspx . Any clues?
Here is the relevant snippet of code:
# Setup Basic EWS Properties for Message Search - Used to locate Hidden Forwarding Rule
$searchFilterForwardRule = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+ContainsSubstring([Microsoft.Exchange.WebServices.Data.ItemSchema]::ItemClass, "IPM.Rule", [Microsoft.Exchange.WebServices.Data.ContainmentMode]::Prefixed, [Microsoft.Exchange.WebServices.Data.ComparisonMode]::Exact)
$itemViewForwardRule = New-Object Microsoft.Exchange.WebServices.Data.ItemView(30, 0, [Microsoft.Exchange.Webservices.Data.OffsetBasePoint]::Beginning)
$itemViewForwardRule.PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties, [Microsoft.Exchange.WebServices.Data.ItemSchema]::ItemClass, [Microsoft.Exchange.WebServices.Data.ItemSchema]::Subject)
$itemViewForwardRule.Traversal = [Microsoft.Exchange.WebServices.Data.ItemTraversal]::Associated
# Properties for Hidden Delegate Forwarding Rule
$PID_TAG_RULE_MSG_PROVIDER = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x65EB,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::String)
$PID_TAG_RULE_ACTIONS = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x6680,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary)
# Property Set for Delegate Forward Rule
$propertySetForwardRule = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties, $PID_TAG_RULE_MSG_PROVIDER)
$forwardRuleExists = $false
$findResults = $service.FindItems([Microsoft.Exchange.Webservices.Data.WellKnownFolderName]::Inbox, $searchFilterForwardRule, $itemViewForwardRule)
If ($findResults.TotalCount -lt 1) {
Write-Error "Failed to find rule" "Error"
} Else {
Foreach ($item in $findResults.Items) {
$item.Load($propertySetForwardRule)
If ($item.ExtendedProperties.Count -ge 1) {
If ($item.ExtendedProperties[0].Value -eq "Schedule+ EMS Interface") {
$forwardRuleExists = $true
write-host "Delegate forwarding rule found." -ForegroundColor Cyan
$propertySetForwardRule.Add($PID_TAG_RULE_ACTIONS)
$item.Load($propertySetForwardRule)
Write-Host "Attempting to retrieve x6680 PR_RULE_ACTIONS (PidTagRuleActions)" -ForegroundColor Cyan
$PR_RULE_ACTIONS = $null
if($Item.TryGetProperty($Pid_Tag_Rule_Actions,[ref]$PR_RULE_ACTIONS)){
return $PR_RULE_ACTIONS
} # endif
else {write-host "TryGetProperty for PR_RULE_ACTIONS failed!" -ForegroundColor Red
} # endelse
} # End If - Correct Message
} # End If - Has Extended Properties
} # End ForEach
} # End If - Message Count
Glen Scales was able to set me on the right path. It turns out that PR_RULE_ACTIONS is not exposed via EWS, but the same data exposed via an attribute called PR_EXTENDED_RULE_ACTIONS. Now I'm happily slinging code to parse the binary blob.
http://msdn.microsoft.com/en-us/library/ee218391(v=EXCHG.80).aspx
The property tag for PR_RULE_ACTIONS is 0x668000FE. You can see it (and the property data) in OutlookSpy (I am its author) - go to the Inbox folder, click IMAPIFolder button, go to the PR_RULES_TABLE tab, select the rule, double click on the PR_RULE_ACTIONS property.
Note that PT_ACTIONS MAPI type (0x000FE) is only accessing in Extended MAPI, I don't think EWS will be able to return it.

Get Tfs Shelveset file contents at the command prompt?

I'm interested in getting the contents of a shelveset at the command prompt. Now, you would think that a cmdlet such as Get-TfsShelveset, available in the TFS Power Tools, would do this. You might also think that "tf.exe shelvesets" would do this.
However, unless I've missed something, I'm appalled to report that neither of these is the case. Instead, each command requires you to give it a shelveset name, and then simply regurgitates a single line item for that shelveset, along with some metadata about the shelveset such as creationdate, displayname, etc. But as far as I can tell, no way to tell what's actually in the shelf.
This is especially heinous for Get-TfsShelveset, which has the ability to include an array of file descriptors along with the Shelveset object it returns. I even tried to get clever, thinking that I could harvest the file names from using -WhatIf with Restore-TfsShelveset, but sadly Restore-TfsShelveset doesn't implement -WhatIf.
Please, someone tell me I'm wrong about this!
tf status /shelveset:name
will list out the content of the named shelveset (you can also supplier an owner: see tf help status).
With the TFS PowerToy's PowerShell snapin:
Get-TfsPendingChange -Shelveset name
for the same information.
It is possible to construct a small command-line application that uses the TFS SDK, which returns the list of files contained in a given shelveset.
The sample below assumes knowledge of the Shelveset name & it's owner:
using System;
using System.IO;
using System.Collections.ObjectModel;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Common;
using Microsoft.TeamFoundation.Framework.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
namespace ShelvesetDetails
{
class Program
{
static void Main(string[] args)
{
Uri tfsUri = (args.Length < 1) ? new Uri("TFS_URI") : new Uri(args[0]);
TfsConfigurationServer configurationServer = TfsConfigurationServerFactory.GetConfigurationServer(tfsUri);
ReadOnlyCollection<CatalogNode> collectionNodes = configurationServer.CatalogNode.QueryChildren(
new[] { CatalogResourceTypes.ProjectCollection },
false, CatalogQueryOptions.None);
CatalogNode collectionNode = collectionNodes[0];
Guid collectionId = new Guid(collectionNode.Resource.Properties["InstanceId"]);
TfsTeamProjectCollection teamProjectCollection = configurationServer.GetTeamProjectCollection(collectionId);
var vcServer = teamProjectCollection.GetService<VersionControlServer>();
Shelveset[] shelves = vcServer.QueryShelvesets(
"SHELVESET_NAME", "SHELVESET_OWNER");
Shelveset shelveset = shelves[0];
PendingSet[] sets = vcServer.QueryShelvedChanges(shelveset);
foreach (PendingSet set in sets)
{
PendingChange[] changes = set.PendingChanges;
foreach (PendingChange change in changes)
{
Console.WriteLine(change.FileName);
}
}
}
}
}
Invoking this console app & catching the outcome during execution of the powershell should be possible.
Try:
tfpt review
/shelveset:shelvesetName;userName
You may also need to add on the server option so something like:
tfpt review /shelveset:Code Review;jim
/sever:company-source
I think this is what you are looking for.
This is what I ended up with, based on pentelif's code and the technique in the article at http://akutz.wordpress.com/2010/11/03/get-msi/ linked in my comment.
function Get-TfsShelvesetItems
{
[CmdletBinding()]
param
(
[string] $ShelvesetName = $(throw "-ShelvesetName must be specified."),
[string] $ShelvesetOwner = "$env:USERDOMAIN\$env:USERNAME",
[string] $ServerUri = $(throw "-ServerUri must be specified."),
[string] $Collection = $(throw "-Collection must be specified.")
)
$getShelvesetItemsClassDefinition = #'
public IEnumerable<PendingChange> GetShelvesetItems(string shelvesetName, string shelvesetOwner, string tfsUriString, string tfsCollectionName)
{
Uri tfsUri = new Uri(tfsUriString);
TfsConfigurationServer configurationServer = TfsConfigurationServerFactory.GetConfigurationServer(tfsUri);
ReadOnlyCollection<CatalogNode> collectionNodes = configurationServer.CatalogNode.QueryChildren( new[] { CatalogResourceTypes.ProjectCollection }, false, CatalogQueryOptions.None);
CatalogNode collectionNode = collectionNodes.Where(node => node.Resource.DisplayName == tfsCollectionName).SingleOrDefault();
Guid collectionId = new Guid(collectionNode.Resource.Properties["InstanceId"]);
TfsTeamProjectCollection teamProjectCollection = configurationServer.GetTeamProjectCollection(collectionId);
var vcServer = teamProjectCollection.GetService<VersionControlServer>();
var changes = new List<PendingChange>();
foreach (Shelveset shelveset in vcServer.QueryShelvesets(shelvesetName, shelvesetOwner))
{
foreach (PendingSet set in vcServer.QueryShelvedChanges(shelveset))
{
foreach ( PendingChange change in set.PendingChanges )
{
changes.Add(change);
}
}
}
return changes.Count == 0 ? null : changes;
}
'#;
$getShelvesetItemsType = Add-Type `
-MemberDefinition $getShelvesetItemsClassDefinition `
-Name "ShelvesetItemsAPI" `
-Namespace "PowerShellTfs" `
-Language CSharpVersion3 `
-UsingNamespace System.IO, `
System.Linq, `
System.Collections.ObjectModel, `
System.Collections.Generic, `
Microsoft.TeamFoundation.Client, `
Microsoft.TeamFoundation.Framework.Client, `
Microsoft.TeamFoundation.Framework.Common, `
Microsoft.TeamFoundation.VersionControl.Client `
-ReferencedAssemblies "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.Client.dll", `
"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.Common.dll", `
"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.VersionControl.Client.dll" `
-PassThru;
# Initialize an instance of the class.
$getShelvesetItems = New-Object -TypeName "PowerShellTfs.ShelvesetItemsAPI";
# Emit the pending changes to the pipeline.
$getShelvesetItems.GetShelvesetItems($ShelvesetName, $ShelvesetOwner, $ServerUri, $Collection);
}
Spent a few days trying to do this as well, this always popped up on google so here is what I found to help future generations:
To get the contents of the shelveset (at least with Team Explorer Everywhere),
use the command: tf difference /shelveset:<Shelveset name>
That will print out the contents of the shelveset and give filenames in the form :
<Changetype>: <server file path>; C<base change number>
Shelved Change: <server file path again>;<shelveset name>
So if your file is contents/test.txt
in the shelveset shelve1 (with base revision 1), you will see :
edit: $/contents/file.txt;C1
Shelved Change: $/contents/file.txt;shelve1
After that, using the tf print command
(or view if not using TEE) on $/contents/file.txt;shelve1 should get you the contents :
tf print $/contents/file.txt;shelve1
Shows you what is in the file.txt in shelveset shelve1
If you want get shelveset changes from server by using tfs command
Using power shell:
Get-TfsPendingChange -Server http://example.com/org -Shelveset shelvsetName
Using vs commands:
c:\projects>tf shelvesets BuddyTest_23
more info about this please see here
https://learn.microsoft.com/en-us/azure/devops/repos/tfvc/shelvesets-command?view=azure-devops