Export-Csv MIM FIM PowerShell Issue - powershell

I was asked to retrieve a .csv list with all users that registered to the FIM portal. I did some searching until I stumbled accross this script:
set-variable -name URI -value "http://localhost:5725/resourcemanagementservice' " -option constant
set-variable -name CSV -value "RegistredResetPassUsers.csv" -option constant
clear
If(#(Get-PSSnapin | Where-Object {$_.Name -eq "FIMAutomation"} ).count -eq 0) {Add-PSSnapin FIMAutomation}
$WFDFilter = "/WorkflowDefinition[DisplayName='Password Reset AuthN Workflow']"
$curObjectWFD = export-fimconfig -uri $URI –onlyBaseResources -customconfig ($WFDFilter) -ErrorVariable Err -ErrorAction SilentlyContinue
$WFDObjectID = (($curObjectWFD.ResourceManagementObject.ResourceManagementAttributes | Where-Object {$_.AttributeName -eq "ObjectID"}).value).split(":")[2]
$Filter = "/Person[AuthNWFRegistered = '$WFDObjectID']"
$curObject = export-fimconfig -uri $URI –onlyBaseResources -customconfig ($Filter) -ErrorVariable Err -ErrorAction SilentlyContinue
[array]$users = $null
foreach($Object in $curObject)
{
$ResetPass = New-Object PSObject
$UserDisplayName = (($Object.ResourceManagementObject.ResourceManagementAttributes | Where-Object {$_.AttributeName -eq "DisplayName"}).Value)
$ResetPass | Add-Member NoteProperty "DisplayName" $UserDisplayName
$Users += $ResetPass
}
$users | export-csv -path $CSV
The script works without errors except that the actual list that it exports only contains my display name. I've been trying to figure out why its not exporting the complete list of all users and only shows my name, but I haven't been able to figure it out so I was wondering if any one could help me shed some light into this issue.
Thanks again for any help you guys can provide!

No experience with this snapin/product, but seeing as the code fundamentally works (it returns your object) this could be a permissions issue. You may not be able to read the other user objects, so they're not being exposed to you.
If you can view them in a UI console of some kind, then check for separate permissions related to API actions, and ensure you have access that way.
Another course of action may be to run the code line by line and see what results you receive from each line, to make sure you get what you're expecting.

Try replacing:
[array]$users = $null
With:
$users = #()

This is likely due to permission setup.
By default you have a permissions to see your own attributes.
There is likely some Management Policy Rule setup so user accounts in a specific Set can read AuthNWFRegistered attribute of other users to support for troubleshooting and customer support.
You will need to use one of the options:
Add the account used for this script into the Set that delegates out this Read permission already
or
Create a separate MPR for this particular reporting (this is what I would recommend) that Grants permissions for a specific user account to read AuthNWFRegistered attribute.
Also make sure there is really only one Workflow that is associated with user registration. If there are multiple, you'd want to target Set with all register Workflows in your XPath filter instead of particular Workflow name.
On a separate note - while FIMAutomation is sometimes necessary snapin to use with standard tooling, for your custom work I strongly suggest to use Lithnet's LithnetRMA PowerShell module (https://github.com/lithnet/resourcemanagement-powershell).
You will be much more productive with it and most of the operations will be without boilerplate code FIMAutomation needs. This will be your code using LithnetRMA.
Set-ResourceManagementClient -BaseAddress 'http://localhost:5725/resourcemanagementservice'
$scope = Search-Resources -XPath "/Person[AuthNWFRegistered = /WorkflowDefinition[DisplayName='Password Reset AuthN Workflow']]" -ExpectedObjectType Person
$scope | select DisplayName | Export-Csv 'RegistredResetPassUsers.csv' -Encoding Unicode

Related

How to use Remove-LocalGroupMember to remove from a server?

I have the following script that is supposed to remove members from a server:
$ssasInstance = ""
$accountName= ""
Import-Module SqlServer
[Microsoft.AnalysisServices.Server]$SSASserver = New-Object ([Microsoft.AnalysisServices.Server])
$SSASserver.Connect($ssasInstance)
$role= $SSASserver.Roles["Administrators"]
$role.Members.Remove($accountName)
$role.Update()
The problem is for some reason Remove() is not really working, no errors generated, but it doesnt remove the user.
I tested the script by instead adding a user, $role.Members.Add($accountName) and this works great! so i know that it must be a bug with the remove() method, and the only option I have is to use Remove-LocalGroupMember
I tried just using it like this:
$ssasInstance = ""
$accountName= ""
Import-Module SqlServer
[Microsoft.AnalysisServices.Server]$SSASserver = New-Object ([Microsoft.AnalysisServices.Server])
$SSASserver.Connect($ssasInstance)
$role= $SSASserver.Roles["Administrators"]
Remove-LocalGroupMember -Group "Administrators" -Member "$accountName"
$role.Update()
but that doesnt work either...although i think its because it doesnt know exactly where its removing from...
I tried this too, but to no avail:
Remove-LocalGroupMember -Group "$role" -Member "$accountName"
So how can i integrate this module into my script?
This is an unfortunate confluence of circumstances: when you do
$role.Members.Add("member")
This works because, under water, the string "member" is implicitly converted by PowerShell to a RoleMember with a Name of member and an empty Sid. All fine. However, if you then do
$role.Members.Remove("member")
Nothing happens, because you will create a new RoleMember instance, and since RoleMember has no implementation of .Equals() (a fairly bizarre oversight), different instances will never be considered the same.
This means you can only remove members by getting the actual instance in the collection (or by index, I suppose):
$member = $role.Members.Where{$_.Name -eq "member"} | Select -First 1
$role.Members.Remove($member)
Note that you will not get an error if there is no such member (because Remove allows $null, again in a rather bizarre oversight), so you may want to check for $member -eq $null if you want to verify that.
Definitely do not use Remove-LocalGroupMember -- that cmdlet is part of a completely different module and removes members from local Windows groups, not SSAS roles.

PowerShell SetAccessRule for ACL failing

The script I've done creates a folder and security groups that is later added to the folder in question with special permissions. The problem is that the script fails on "$acl.SetAccessRule($rule_modify)" and complains about the identity.
Error:
"Exception calling "SetAccessRule" with "1" argument(s): "Some or all identity references could not be translated."
If I run the script row by row by simply using copy/paste from ISE into a regular PowerShell window everything goes through without errors using the same location and user.
This is the important bit that isn't working.
#Get ACL list
$acl = Get-Acl -Path $Path
$acl.SetAccessRuleProtection($false,$false)
#Add permission for modify
$set_modify = "INTRA\FIL_$($Department)_$($Group)_Modify", 'DeleteSubdirectoriesAndFiles, Write, ReadAndExecute, Synchronize', 'ContainerInherit, ObjectInherit', 'None', 'Allow'
$rule_modify = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $set_modify
$acl.SetAccessRule($rule_modify)
$acl | Set-Acl $path
I had basicly the same issue but with "AddAccessRule".
$Acl.AddAccessRule($Ar)
My Script failed with the above mentioned error.
Just as Patrik Persson mentioned, in my case it was also because AD was slow on showing new groups and the Ar could not be added until the security group showed up in my AD.
So i added a try/catch with a do/until loop to my script which i want to share:
do {
$check = 'ok'
try {
$Acl.AddAccessRule($Ar)
} catch [System.Management.Automation.RuntimeException] {
$_.Exception.Message
$check = 'error'
Start-Sleep -Seconds 2
}
} until (
$check -eq 'ok'
)
So the loop continues until AD registers the security group correctly. After that the Ar is added to the acl and my script continues as expected.
I have found the solution and it fails because ActiveDirectory is too slow to recognize that the security group is created propery before adding it to the ACL.
Solution I went with was to add a 10 second sleep after groups and folder was created and it now works as intended.
You might want to expand all the strings you're using to build your security group name into a clean variable - I find that can be touchy. Make sure that $secgroup contains the right string value when you've constructed it.
You can create the rule together with the object type on one line as well.
$secgroup = "INTRA\FIL_$($Department)_$($Group)_Modify"
$modifyRule = New-Object System.Security.AccessControl.FileSystemAccessRule($secgroup,'DeleteSubdirectoriesAndFiles, Write, ReadAndExecute, Synchronize','ContainerInherit, ObjectInherit','None','Allow')
By the way, if essentially you want your users to have Modify rights on the contents without being able to delete the parent folder, it should work if you set the InheritOnly flag (I haven't tested it).
$modifyRule = New-Object System.Security.AccessControl.FileSystemAccessRule($secgroup,'Modify, Synchronize', 'ContainerInherit, ObjectInherit','InheritOnly','Allow')
Had a similar issue while creating shares on remote file servers.
At first, I'd used the proposed solution (start-sleep), but it was not good enough as it significantly increased the time consumed while processing a lot of shares.
It turns out that you may use SID while defining your ACE and operation is instant:
$TempSID = (Get-ADGroup "FIL_$($Department)_$($Group)_Modify").SID
$PermissionModify = "Write, Read, ListDirectory, ReadAndexecute, DeleteSubdirectoriesAndFiles"
$Inherit = [system.security.accesscontrol.InheritanceFlags]"ContainerInherit, ObjectInherit"
$Propagation = [system.security.accesscontrol.PropagationFlags]"None"
$Type = "Allow"
$modifyRule = New-Object System.Security.AccessControl.FileSystemAccessRule($TempSID, $PermissionModify, $Inherit, $Propagation, $Type)
Seems that Active Directory needs some time (in my case 2 seconds) to translate SID to the group name (in DOMAIN\groupName format).
Another case: I have got the error Exception calling SetAccessRule... because I have set the account without the domain, so - with the question's example - I have put .\FIL_$($Department)_$($Group)_Modify instead of INTRA\FIL_$($Department)_$($Group)_Modify.

Setting a DateTime to $null/empty using PowerShell and the SCSM cmdlets

I'm currently trying to sync additional attributes from the AD (Active Directory) for user objects in SCSM (System Center Service Manager) using a PowerShell script.
The extension I wrote for this, includes an attribute for the expiration date of a AD user account (DateTime value, named DateTimeAttribute in the example) if the user account doesn't expire it should be empty/null.
Using Import-SCSMInstance, which should be similar to a CSV import, it kind of works by passing "null" for the field. The problem is that Import-SCSMInstance seems to be quite unreliable and it doesn't offer any kind of information of why it works or doesn't work. Using Update-SCSMClassInstance seems to work a lot better but I can't figure out a way to clear the field using this and even using [DateTime]::MinValue will result in an error, stating that it's an invalid value.
So would anyone have an idea on how to clear the value using Update-SCSMClassInstance or figure out why Import-SCSMInstance might or might not work?
A simple example for this could look like the following:
$server = "<ServerName>"
$extensionGuid = "<GUID>"
Import-Module 'C:\Program Files\System Center 2012 R2\Service Manager\Powershell\System.Center.Service.Manager.psd1'
New-SCManagementGroupConnection -ComputerName $server
$extensionClass = Get-SCSMClass -Id $extensionGuid
$scsmUserObject = Get-SCSMClassInstance -Class $extensionClass -Filter 'UserName -eq "<User>"'
# Error
$scsmUserObject.DateTimeAttribute = ""
# Works but fails on Update-SCSMClassInstance
$scsmUserObject.DateTimeAttribute = $null
$scsmUserObject.DateTimeAttribute = [DateTime]::MinValue
# Works
$scsmUserObject.DateTimeAttribute = "01-01-1970"
Update-SCSMClassInstance -Instance $scsmUserObject
It seems that you can't clear a date once it's filled. When you write $null, it sets the date to 1-1-0001 01:00:00, which is an invalid date causing the update-scsmclassinstance to fail.
What we have set as a user's AD property when we don't want something to expire, is 2999-12-31 (yyyy-MM-dd). Perhaps this could help, although it's not directly what you asked for...
Also, you can use the pipeline to update a property in SCSM:
Get-SCSMClassInstance -Class $extensionClass -Filter 'UserName -eq "<User>"' | % {$_.DateTimeAttribute = <date>; $_} | update-scsmclassinstance
It doesn't look like it's currently possible to clear custom date attributes using the PowerShell cmdlets.

Powershell - Can't figure out how to get web content from IE object

I am pretty new to Powershell and just using it for personal stuff. I have been experimenting with pulling specific info from websites to include in emails to family. By reading the forums I got pretty good using the Invoke-WebRequest cmdlet, but soon hit upon its limitation of not having access to content constructed dynamically at the time the page is loaded.
Thanks to these forums, I then discovered the IE object and how to pull the data. I had luck with one website, but another I tried does not work the same. Hoping for a little help figuring it out.
Here is a snippet of the inspected code for the page, with my target of interest highlighted.
Below is the code where I am trying to extract that text string. I have tried many iterations and approaches with no success. What is odd, though, the $ie.Document object supposedly has a "body" object, but when I tried to access it, I get a null object error. I notice the Document object itself has a getElementsByTagName method, so I tried that. It does not have a getElementsByClassName method.
Note that the URL I am loading is "https" so I am wondering if this is causing issues. Suggestions appreciated! If I can just get a surrounding chunk of the HTML, I am fine doing some string manipulation to get what I want.
# Create IE object and load URL
$WeatherURL = "https://weather.com/weather/today/l/77630"
$ie = New-Object -comobject "InternetExplorer.Application"
$ie.visible = $true
$ie.navigate($WeatherURL)
# Wait for the page to load
while ($ie.Busy -eq $true -Or $ie.ReadyState -ne 4) {Start-Sleep 2}
$Doc = $ie.Document
$Weather0 = $Doc.getElementsByTagName('span') `
| ?{$_.getAttribute('class') -eq "today-wx-descrip"} | Select-Object -First 1
You should replace
$Weather0 = $Doc.getElementsByTagName('span') `
| ?{$_.getAttribute('class') -eq "today-wx-description"} | Select-Object -First 1
With
$Weather0 = $Doc.getElementsByTagName('span') `
| ?{$_.getAttribute('class') -eq "today-wx-descrip"} | Select-Object -First 1
Note today-wx-description vs today-wx-descrip.

Searching AD Groups attached to specified Server

I'm looking to use powershell, specify a server hostname, and have it display all the AD Groups that have access to that server. From there I'll dig into the groups eventually getting the usernames and storing them in a csv file.
So far I have the code to get the DN of the server -
Get-adcomputer HOSTNAME | select DistinguishedName
Along with having the code to get the eventual usernames and store them in a csv -
$groups= GROUPS
$selectgroups=$groups |Get-Adgroup
$selectgroups |get-adgroupmember -Recursive | Select samaccountname |
Export-csv -path C:\Groups\Members.csv -NoTypeInformation
My problem is I can't figure out how to get powershell to query what groups are on the server I specify. Is this possible or will I have to look at another way of doing this?
Thanks.
Not sure you know exactly what you're looking for. There's no way to tell which AD groups have been granted access to a node via AD. The only thing you can do is look on the local node for AD groups, but there's a lot of places you could want/need to look as Frode F. mentioned already. A common theme would be which AD groups have been added to LOCAL groups on the node in question.
You could use WMI or the ADSI adapter for this information. An ADSI example to get all members of the 'Administrators' local group for server 'NODE123':
$server = "NODE123"
$arrGroupMembers=#()
$Group = "Administrators"
$ADSIComputer = [ADSI]("WinNT://" + $server + ",computer")
$ADSIGroup = $ADSIcomputer.psbase.children.find($Group)
$ADSIMembers= $ADSIGroup.psbase.invoke("Members")
foreach ($member in $ADSIMembers) {
$MemberClass = $member.GetType().InvokeMember("Class", 'GetProperty', $Null, $member, $Null)
if ($memberClass -eq "Group") {
$MemberName = $member.GetType().InvokeMember("Name", 'GetProperty', $Null, $member, $Null)
$arrGroupMembers+=$MemberName
}
}
With the array return above, you now have all groups that have access to NODE123 via being added to the local Administrators group. Maybe this example helps you.