Simple really, I have a PS script ready to go but I would like to pipe the results of adding 1000 names to an AD security group with Add-ADGroupMember. Problem is ADD-Adgroupmember doesn't return any results. What would be the best way to do this?
You can wrap the call in a try/catch block:
$Group = Get-ADGroup "myGroup"
$Users = "habanagold","habanasilver","mrceo"
foreach($User in $Users){
try {
Add-ADGroupMember -Identity $Group -Members $User -ErrorAction Stop
"$User added to $Group" | Out-File C:\path\to\output.log -Append
} catch {
"Failed to add $User to $Group" | Out-File C:\path\to\output.log -Append
}
}
Related
i imported from file IDs and base on this ID i am trying to get information from AD...and insert this information as columns in original file...this is the code:
$import = Import-Csv C:\Temp\coputerstatus.csv
Foreach ($item in $import) {
$user = Get-ADUSer -Identity $item.ID
#$item = New-Object psobject
$item | Add-Member -MemberType NoteProperty -Name "office" -Value $user.office
$item | Add-Member -MemberType NoteProperty -Name "title" -Value $user.title
$item | Add-Member -MemberType NoteProperty -Name "displayname" -Value $user.name
} #foreach
$import | Export-Csv C:\temp\my.csv
but it is no working very well..i success to insert the headers but the value is empty(,,,)
i would like to same help
thanks
Get-ADUser and other active directory cmdlets operate a little funny. When you ask for an ADUser object Get-ADuser only returns a small subset of the properties available. Office and title are not available in this default set. To get what you want add the -Property parameter to Get-ADUser and ask for title and office in addition to the defaults it normally returns
$user = Get-ADUSer -Identity $item.ID -Property Title, Office
if you want to retrieve all possible properties use an asterisk
$user = Get-ADUSer -Identity $item.ID -Property *
It actually sounds like you may not be getting any user object back from Get-ADUser. Have a look at what is in the ID column in your csv files. Manually check what you are getting back from the import-csv command
$import = Import-Csv C:\Temp\coputerstatus.csv
$import | gm
Make sure that you have an ID property in that list. If so go ahead and check if your objects have ID values that you expect
$import.ID
If everything looks fine there try taking one of those IDs and manually running the Get-ADuser command replacing $item.ID with one of the actual IDs.
Get-ADUSer -Identity TESTID -Property Title, Office
Do you get anything back?
Two ways...you can use splatting to dump all of the properties into the CSV for each like this...
$import = Import-Csv C:\Temp\coputerstatus.csv
$myUsers = #()
Foreach ($item in $import) {
$user = Get-ADUSer -Identity $item.ID -Properties *
[pscustomobject]$MyItem = #{
"userProps" = $user
}
$myUsers += $MyItem.Values
} #foreach
$myUsers | Export-Csv 'C:\temp\my.csv' -NoTypeInformation
Or you can select specific properties that you care about, like this...
$import = Import-Csv C:\Temp\coputerstatus.csv
$myUsers = #()
Foreach ($item in $import) {
$user = Get-ADUSer -Identity $item.ID -Properties *
[pscustomobject]$MyItem = #{
"DisplayName" = $user.Name
"Office" = $user.office
"Title" = $user.title
}
$myUsers += $MyItem.Values
} #foreach
$myUsers | Export-Csv 'C:\temp\my.csv' -NoTypeInformation
Hi Im trying to write a script to replace nested groups with members of said group. I found one from https://community.spiceworks.com/topic/1816091-ad-powershell-replace-nested-groups-with-members-of-said-group
and modified as follows. Where #Parent_1 is an AD distribution group.
$TargetGroup= '#Parent_1'
ForEach ($Member in Get-ADGroupMember -Identity $TargetGroup) {
if ($Member.objectclass -eq 'group') {
ForEach ($SubMember in Get-ADGroupMember -Identity $Member -Recursive ) {
Add-ADGroupMember -Identity $TargetGroup -Members $SubMember.SamAccountName
}
Remove-ADGroupMember -Identity $TargetGroup -Members $Member -Confirm:$false
}
}
It works perfectly fine for a single group that is "#Parent_1" when used as $TargetGroup.
But I wish to run it more than one for $TargetGroup using a CSV as follows.
Instead of using $TargetGroup= '#Parent_1', I wish to have $TargetGroup =Import-Csv -Path .\xx.csv
With the following CSV.
But it won't run, just by replacing that. It just gives errors.
Did several modifications, yet casting different different errors time to time, could not make it. Not sure we need another for each loop.
Can anyone please help ? Any help would be appreciated.
PS answer for my question | Final working code
foreach($TargetGroup in Import-Csv -Path .\xx.csv)
{
ForEach ($Member in Get-ADGroupMember -Identity $TargetGroup.samaccountname)
{
if ($Member.objectclass -eq 'group')
{
ForEach ($SubMember in Get-ADGroupMember -Identity $Member -Recursive)
{
Add-ADGroupMember -Identity $TargetGroup.samaccountname -Members $SubMember.SamAccountName
}
Remove-ADGroupMember -Identity $TargetGroup.samaccountname -Members $Member -Confirm:$false
}
}
}
You just need to loop one $TargetGroup at a time
foreach($TargetGroup in Import-Csv -Path .\xx.csv)
{
ForEach ($Member in Get-ADGroupMember -Identity $TargetGroup)
{
if ($Member.objectclass -eq 'group')
{
ForEach ($SubMember in Get-ADGroupMember -Identity $Member -Recursive)
{
Add-ADGroupMember -Identity $TargetGroup -Members $SubMember.SamAccountName
}
Remove-ADGroupMember -Identity $TargetGroup -Members $Member -Confirm:$false
}
}
}
#Doug thanks.. $TargetGroup should be $TargetGroup.samaccountname for internal loops in this way.. and its works! perfect.
foreach($TargetGroup in Import-Csv -Path .\xx.csv)
{
ForEach ($Member in Get-ADGroupMember -Identity $TargetGroup.samaccountname)
{
if ($Member.objectclass -eq 'group')
{
ForEach ($SubMember in Get-ADGroupMember -Identity $Member -Recursive)
{
Add-ADGroupMember -Identity $TargetGroup.samaccountname -Members $SubMember.SamAccountName
}
Remove-ADGroupMember -Identity $TargetGroup.samaccountname -Members $Member -Confirm:$false
}
}
}
I've tried the following few bits and i'm trying to create a function to insert into another powershell script
function start-OService{
Get-Service service1|?{$_.Status -eq 'Stopped'}|Start-Service
Get-Service service2|?{$_.Status -eq 'Stopped'}|Start-Service
}
And this one ...
function start-OService {
$services = 'service1', 'service1'
Get-Service | ? {
$services -contains $_.Name -and $_.Status -eq 'Stopped'
} | Start-Service
}
The first snippet doesn't seem to run correctly but i'm not getting an error. I can run each line individually but not the way I have it setup.
The 2nd one was my original attempt that was taken from another SO question. The Get-Service doesn't seem to like the $services variable having multiple services contained.
Try this:
function start-OService {
$services = 'service1', 'service1'
foreach ($service in $services)
{
if ((Get-Service $service).Status -eq "Stopped")
{
Start-Service $service
}
}
}
One liner:
"service1", "service2" | Get-Service | ?{ $_.Status -eq "Stopped" } | Start-Service
For starting all the services which was stopped at a given time, below script will be helpful
$StoppedServices=Get-Service | where {$_.Status -eq "Stopped"}
foreach ($item in $StoppedServices)
{
$Name=$item.Name
Start-Service -Name $Name
}
function start-OService {
$services = 'service1', 'service1'
$services | % {
$service = get-service -name $_;
if($service.Status -eq [System.ServiceProcess.ServiceControllerStatus]::Stopped)
{
Write-Output "Starting $_"
$service.Start()
}
}
}
In the following script, it will print all the users of the groups. However, the domain name is missing (Some users are in different Windows domain)?
$computer = [ADSI]"WinNT://$server,computer"
$computer.psbase.children | ? {
$_.psbase.schemaClassName -eq 'group'
} | % {
$gn = $_.name.ToString()
write-host $gn
write-host "------"
$group =[ADSI]$_.psbase.Path
$group.psbase.Invoke("Members") | % {
$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
}
}
Try fetching the SID instead of the name and translate that back to a username:
$computer.psbase.children | ? {
$_.psbase.schemaClassName -eq 'group'
} | % {
$gn = $_.name.ToString()
write-host $gn
write-host "------"
$group =[ADSI]$_.psbase.Path
$group.psbase.Invoke("Members") | % {
$bytes = $_.GetType().InvokeMember('objectSid', 'GetProperty', $null, $_, $null)
$sid = New-Object Security.Principal.SecurityIdentifier ($bytes, 0)
$sid.Translate([Security.Principal.NTAccount])
}
}
The result should include the computer or domain name.
We have a similar issue where there are accounts from different domains on the computers and we need the domain back. Unfortunately the SID fetch doesn't work I think for local accounts and the domains the computer used to be joined to in some cases, so it didn't return all results.
This was the best solution I found for us:
Admin = $_.GetType().InvokeMember("AdsPath", 'GetProperty', $null, $_, $null)
will return results like
WinNT://#domain#/#account#
or WinNT://#domain of computer#/#computer-name#/#account#
for local accounts
$servers= get-content 'C:\temp\work\localadmins\serverlist_in.txt'
$output = 'C:\temp\work\localadmins\serverlist_out.csv'
$results = #()
foreach($server in $servers)
{
$admins = #()
$group =[ADSI]"WinNT://$server/Administrators"
$members = #($group.psbase.Invoke("Members"))
$members | foreach {
$obj = new-object psobject -Property #{
Server = $Server
Admin = $_.GetType().InvokeMember("AdsPath", 'GetProperty', $null, $_, $null)
}
$admins += $obj
}
$results += $admins
}
$results | Export-csv $Output -NoTypeInformation
Is there a simple way using powershell to show all Local Windows Groups that are active on a machine and the users that are part of those groups? A second part of this question would be if it can be extended to look at more than one machine at a time.
In fact you can with the ADSI type shortcut and the WinNT moniker. Here's an example to list groups and members from your own machine:
$server="."
$computer = [ADSI]"WinNT://$server,computer"
$computer.psbase.children | where { $_.psbase.schemaClassName -eq 'group' } | foreach {
write-host $_.name
write-host "------"
$group =[ADSI]$_.psbase.Path
$group.psbase.Invoke("Members") | foreach {$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}
write-host
}
Powershell does not have any inherent support for such a feature. However it's easy to wrap the "net localgroup" command with a couple of powershell functions and thus enable it in the pipeline.
Get Local Groups
function Get-LocalGroups() {
net localgroup | ?{ $_ -match "^\*.*" } | %{ $_.SubString(1) };
}
Get Local Group members
function Get-LocalGroupMembers() {
param ([string]$groupName = $(throw "Need a name") )
$lines = net localgroup $groupName
$found = $false
for ($i = 0; $i -lt $lines.Length; $i++ ) {
if ( $found ) {
if ( -not $lines[$i].StartsWith("The command completed")) {
$lines[$i]
}
} elseif ( $lines[$i] -match "^----" ) {
$found = $true;
}
}
}
Below is an improved version of Shay Levy's script which works for local groups with "orphaned" accounts which SIDs can't be resolved.
$server = "$env:COMPUTERNAME"
$computer = [ADSI]"WinNT://$server,computer"
$computer.psbase.children | where { $_.psbase.schemaClassName -eq 'group' } | foreach {
write-host $_.name
write-host "------"
$group =[ADSI]$_.psbase.Path
$group.psbase.Invoke("Members") | foreach {$_."GetType".Invoke().InvokeMember("Name", 'GetProperty', $null, $_, $null)}
write-host
}
Jay Levy's answer turned into a function :)
Function Get-LocalGroupMembers
{
Param(
[string]
$server = "."
)
Try
{
$computer = [ADSI]"WinNT://$( $Server ),computer"
$computer.psbase.children |
where {
$_.psbase.schemaClassName -eq 'group'
} |
ForEach {
$GroupName = $_.Name.ToString()
$group =[ADSI]$_.psbase.Path
$group.psbase.Invoke("Members") |
foreach {
$memberName = $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null) -replace "WinNT:", ""
$props = #{
"LocalGroup" = $GroupName
"MemberName" = $memberName
}
$obj = New-Object -TypeName psobject -Property $props
Write-Output $obj
} # foreach members
} # foreach group
}
Catch
{
Throw
}
}
To get the local group members
Get-LocalGroupMembers
To get the local group members for another machine
Get-LocalGroupMembers -Server $Computer