I'm using Powershell 5.1 in constrained language mode with no access to additional modules.
I've created a script to return information from "net user query (username) /domain" that includes an If statement to return results if the end user I'm checking isn't a member of certain groups.
The If statement doesn't appear to be working correctly and I'm not sure where I'm going wrong.
1.
$enduser = read-host "please enter username"
Net user query $enduser /domain
$u = #{}; net user $enduser /domain | ConvertFrom-String -Delimiter '\s{2,}' -PropertyNames Name,
Value | ForEach-Object { $u[$_.Name] = $_.Value }
$globalgroups = $u_.'global group memberships'
if ($globalgroups) -inotlike '$_.EXAMPLEGROUPNAME'
{
write-output "user is not part of EXAMPLEGROUP"
}
I have also tried
2.
if ($globalgroups) -inotlike '*EXAMPLEGROUPNAME*'
{
write-output "user is not part of EXAMPLEGROUP"
}
3. as well as creating new variables
$EXAMPLEGROUP1 = { $u[$_.'global group memberships'] = $_.'EXAMPLEGROUPNAME' }
$EXAMPLEGROUPtest = { $u[$_.'global group memberships'] = $_.'value' }
and changing the if statement to;
if ($globalgroups) -inotlike '$examplegroup1'
{
write-output "user is not part of EXAMPLEGROUP"
}
the #2 snippet of code appears to work for one specific group which always appears as the first result in global group memberships, however if a different group name is added which appears later in the list of global group memberships, it always returns that the user isn't part of the group, even though I can see it there.
What can I change to make this work?
I am not sure why exaclty you are using Net user query. But as far as i can see, you try to make an If statement to return results if the end user you are checking isn't a member of certain groups in Active Directory.
I would rather than using Net user query do something like this:
$enduser = "TestUser"
$examplesgroupname = "Test-Group"
$groupmembership = Get-ADPrincipalGroupMembership $enduser
foreach ($membership in $groupmembership.name) {
if ($membership -ne $examplesgroupname) {
$membership_validated = $true
##statement Is true when user is not member of the examplegroup
} else {
$membership_unvalidated = $false
##statement Is false when user is member of the examplegroup
}
}
Write-Host $membership_validated
If you need to use Net user query for a certain reason, than give a short feedback and i will try to fix your script with Net user query included.
Related
I'm having trouble getting a small PS script to work the way I want it to.
Powershell version: 5.1
Ultimate goal: I want to parse all existing local User accounts and generate a list of those that are not part of any local Groups. (This is not an AD environment, nor part of a domain. This is all just local OS accounts and Groups.) Also, I am only interested in the Groups that I have manually created - I don't care about the default System Groups. (More on how I try to achieve this, later.) And then, after I get this part working, this output (list of User names) will then be used (in the future - not shown in this code) as input to another block that will add these not-in-a-Group users to a Group.
I found an example bit of code - which worked, and resulted in the correct set of user names. But it was slow - it took >5 minutes. So I wanted something faster.
The approach that I'm working with now generally seems like it will work, and is pretty quick. I'm just having trouble getting it to restrict things down correctly. It seems I'm having trouble referencing properties of objects returned by the cmdlets. (See code a bit further down. There are various counters and write-host steps in here, too, that are purely for helping me see what's going on and debugging - they aren't required for the actual task.)
My general outline of how I am going about this:
Compile a list of all Users in all Groups
But, I only want Groups that have no Description - these are the ones that I have created on the machine. The OS default Groups all have a Description. This will help me narrow down my list of Users.
Loop over the list of all Users on the system
Compare each user to the List from Step 1
If User is on the List, then that User is IN a Group, so skip it
If User is not on the List, then save/report that Name back
[Side note - the user 'WDAGUtilityAccount' turned out to also not be in any Groups, but I don't want to change that one; so have a specific test to exclude it from the list.]
[original version of code]
# --- Part 1
$UsersList = foreach ( $aGroup in get-localgroup ) {
$groupcount++
# Only want Groups that don't have a Description
if ( $null -eq $aGroup.Description ) {
Get-LocalGroupMember $aGroup.name
}
write-host "$groupCount -- $aGroup.Name _ $aGroup.Description"
}
# Just for debugging - to see the content of Part 1
write-host "List = $UsersList"
# ---- Part 2
Get-LocalUser | ForEach-Object {
$count++
$name = $_.Name
if ( $name -eq "WDAGUtilityAccount" ) {
# nothing - skip this one
} elseif ( $UsersList.Name -inotcontains "$env:COMPUTERNAME\$_" ) {
$count2++
write-host "$Count ($Count2) : $name -- not a part of any groups"
}
}
It appears that my attempts to extract the Properties of the Group in Part 1 are failing - I am getting literal text 'Name' and 'Description', instead of the aGroup.Name aGroup.Description property values. So my output looks like "MyGroup1.Name" instead of "MyGroup1" (assuming the actual name of the group is 'MyGroup1').
I believe that I am approaching the 'Group' object correctly - when I do 'get-localgroup | get-member" it says that it is a 'LocalGroup' object, with various properties (Name and Description being two of those).
There may be many other approaches to this - I'm interested in hearing general ideas; but I would also like to know the specific issues with my current code - it's a learning exercise. :)
Thanks, J
[ Version 2 of code - after some suggestions... ]
$UsersList = foreach ( $aGroup in get-localgroup ) {
$groupcount++
#Write-Host $aGroup.Description
# Only want Groups that don't have a Description (i.e. are the Groups that we created, not the default System/OS groups)
if ( $null -eq $($aGroup.Description) ) {
$UserList += Get-LocalGroupMember $($aGroup.name)
write-host "$groupCount -- $($aGroup.Name) _ $($aGroup.Description)"
}
}
write-host "List = $UsersList"
Get-LocalUser | ForEach-Object {
$count++
$name = $_.Name
if ( $name -eq "WDAGUtilityAccount" ) {
# nothing - skip this one
} elseif ( $($UsersList.name) -inotcontains "$env:COMPUTERNAME\$_" ) {
$count2++
write-host "$Count ($Count2) : $name -- not a part of any groups"
}
}
I believe this could be reduced to:
Store all members of a any group where the group's Description is null.
Get all local users and filter where their user's Name is not equal to WDAGUtilityAccount and they are not part of the stored member's SID array.
$members = Get-LocalGroup | Where-Object { -not $_.Description } | Get-LocalGroupMember
Get-LocalUser | Where-Object {
$_.Name -ne 'WDAGUtilityAccount' -and $_.SID -notin $members.SID
} | Format-Table -AutoSize
so what i want to do is use powershell to list all ADusers into a basic interactive menu so that a specific user can be chosen and removed.
This is what I got so far, and this all users and allows me to select a specific one. But the Remove-ADUser -identity $ouEntry (on line: 18) runs right after I start the script and selects all the users for removal before I can select a specific one. I need it to run after i select an option, and with the correct user. I have been looking into a switch menu, but with poor results since I cant embed the ForEach properly.
Appreciate all help. I'm also open to alternate solutions
Clear-Host
$ouCounter = 1
$MenuArray = #()
$DomainName = ($env:USERDNSDOMAIN).split('.')[0]
$Tld = ($env:USERDNSDOMAIN).split('.')[1]
Write-Host "`nChoose the user you want to delete"
foreach ($ouEntry in ((Get-ADUser -SearchBase "DC=$DomainName,DC=$Tld" -Filter *).name))
{
$(" "+$ouCounter+".`t"+$ouEntry)
$ouCounter++
$MenuArray += $ouEntry + " was removed"
$MenuArray += Remove-ADUser -identity $ouEntry
}
do
{ [int]$menuSelection = Read-Host "`n Enter Option Number"}
until ([int]$menuSelection -le $ouCounter -1)
$MenuArray[ $menuSelection-1]
Output
Choose the user you want to delete
1. Administrator
2. Guest
3. user1
4. user2
5. user3
6. user4
7. user5
8. user6
9. Jon Snow
Enter Option Number:
Previous reference: Making a dynamic menu in Powershell
You might consider doing this in a Windows Forms GUI, so the list to choose from can have a scrollbar.
Having said that, the code you have now writes the entry on screen as menu item and immediately removes that user.
Below code first gets the users in an array once and creates a List object from that.
The reason for using a List object is because with that it is easy to remove an item (unlike with using an array).
$DomainName = ($env:USERDNSDOMAIN).Split('.')[0]
$Tld = ($env:USERDNSDOMAIN).Split('.')[1]
# get an array of users in the given OU, sorted on the Name property
$users = Get-ADUser -SearchBase "DC=$DomainName,DC=$Tld" -Filter * | Sort-Object Name
# store them in a List object for easy removal
$list = [System.Collections.Generic.List[object]]::new()
$list.AddRange($users)
# now start an endless loop for the menu handling
while ($true) {
Clear-Host
# loop through the users list and build the menu
Write-Host "`r`nChoose the user you want to delete. Press Q to quit." -ForegroundColor Yellow
$index = 1
$list | ForEach-Object { " {0}.`t{1}" -f $index++, $_.Name }
$menuSelection = Read-Host "`r`nEnter Option Number."
# if the user presses 'Q', exit the loop
if ($menuSelection -eq 'Q') { break }
# here remove the chosen user if a valid input was given
if ([int]::TryParse($menuSelection, [ref]$index)) {
if ($index -gt 0 -and $index -le $list.Count) {
$userToDelete = $list[$index - 1]
Write-Host "Removing user $($userToDelete.Name)" -ForegroundColor Cyan
Remove-ADUser -Identity $userToDelete.DistinguishedName
# remove the user from the list
$list.RemoveAt($index - 1)
}
}
# add a little pause and start over again
Start-Sleep -Seconds 1
}
Hope that helps
I have to make a script in PowerShell that shows all groups that user belongs to. What's more, if the switch -ListAllMembers is on, it should also show all members of these groups. The thing is that my script shows all members of different groups as one object (array) and I want them to be divided. Get-LocalGroupMember command is in a foreach loop. What can I do?
Param(
$userToCheck,
[switch]$listAllMembers
)
function CheckIfBelongs {
foreach ($user in Get-LocalGroupMember $args[0]) {
if ($user.Name -eq ($env:USERDOMAIN + "\" + $args[1])) {
return $true
}
}
return $false
}
if (!$userToCheck) {
$userToCheck = $env:USERNAME
}
Write-Host "`nUser $userToCheck belongs to these local groups:`n"
foreach ($group in Get-LocalGroup) {
if (CheckIfBelongs $group $userToCheck) {
Write-Host $group.Name
if ($listAllMembers) {
Get-LocalGroupMember $group
}
}
}
exit 0
Write-Host writes directly to the host console. Default output (as produced by Get-LocalGroupMember) goes to the success output stream. Output order is not guaranteed across streams. Also, PowerShell default formatting suppresses additional table headers when outputting objects of the same type as a table. Because of that you see only one table, and the host output before that table.
Change Write-Host to Write-Output and the output will become what you expect.
Finally, I managed to solve the issue. I used Out-String to convert the object to a string and then to send it to the console. Now, it works perfectly.
A bit of context, I am trying to get a list of users from a security group, then check if any of those users do not have an assigned XenDesktop.
Please forgive me, I only started using Powershell yesterday so my formatting is off. It first grabs the users from the AD group then checks if that user has an assigned desktop, which works but I what I can't seem to get working is that if the user is found in that list, I want it to move onto the next username, instead it continues to check against every machine and then onto the final bits of code.
$checkusernames = Get-ADGroupMember "***AD security Group***" | Select SamAccountName
$desktops = get-brokerdesktop -DesktopGroupName Personal_WIN8 | Select MachineName, #{Name='AssociatedUserNames';Expression={[string]::join(“;”, ($_.AssociatedUserNames))}}
foreach ($username in $checkusernames.SamAccountName) {
foreach ($desktop in $desktops) {
If ($desktop.AssociatedUserNames -like "*$username*") {
write-host $username "is assigned to" $desktop.machinename
}
write-host $username "is not assigned to a desktop"
}
Write-host $username "is not assigned to anything"
pause
}
If you want to exit from a ForEach loop early you can do so with the Break keyword. For example:
$checkusernames = Get-ADGroupMember "***AD security Group***" | Select SamAccountName
$desktops = get-brokerdesktop -DesktopGroupName Personal_WIN8 | Select MachineName, #{Name='AssociatedUserNames';Expression={[string]::join(“;”, ($_.AssociatedUserNames))}}
foreach ($username in $checkusernames.SamAccountName) {
$machine = ''
foreach ($desktop in $desktops) {
If ($desktop.AssociatedUserNames -like "*$username*") {
$machine = $desktop.machinename
break
}
}
If ($machine) {
write-host $username "is assigned to" $desktop.machinename
} Else {
write-host $username "is not assigned to a desktop"
pause
}
}
This will stop the current cycle of the inner ForEach loop (once it has completed in it's entirety) without interrupting the ongoing cycle of the outer one.
Per the dicussion in the comments, i've also reorganised the code so that you only get a single output dependent on whether a desktop is matched to a user or not and it only pauses if it does not find a match.
I have a hash table here and I have it eventually outputting to an Excel spreadsheet, but the issue appears to be the way the system sorts the hash table by default. I want it to return the machines in the same order that they are inputted, they way it currently works is a box pops up and you paste in all your machine names so they are all in memory prior to the foreach loop. I was previously sorting this by the longest uptime but it now needs to be the same way they are inputted. My initial thought is to create another hash table and capture them in the same order versus the $machineList variable, but that might even leave me in the same position. I tried to search but I couldn't find info on the default way that hash tables sort.
Any ideas?
$machineUptime = #{}
foreach($machine in $machineList){
if(Test-Connection $machine -Count 1 -Quiet){
try{
$logonUser = #gets the logged on user
$systemUptime = #gets the wmi property for uptime
if($logonUser -eq $null){
$logonUser = "No Users Logged on"
}
$machineUptime[$machine] = "$systemUptime - $logonUser"
}
catch{
Write-Error $_
$machineUptime[$machine] = "Error retrieving uptime"
}
}
else{
$machineUptime[$machine] = "Offline"
}
}
Create $machineUptime as an ordered hashtable (provided you have PowerShell v3 or newer):
$machineUptime = [ordered]#{}