I have been using the following command to pull the list of membership for a given machinename:
Get-ADPrincipalGroupMembership -Identity (Get-ADComputer <MACHINENAME>)
| select-object name | Out-File C:\mydir\MemberShip.csv
The membership identifies software associated to a machine such as Adobe Acrobat Pro, MS Project, etc. Sometimes the software is associated but not actually installed which is why I use the query to validate this information against another list. I am trying to run a query to pull the membership for a list of assets in a text file and export with the name of each computer and the membership for each as well. Maybe get it to display something like the following:
NAME NAME
----------- -------------
<MACHINENAME1> ADOBE ACROBAT PRO
MS PROJECT STD
MS VISIO PRO
<MACHINENAME2> ADOBE ACROBAT PRO
ADOBE PHOTOSHOP
I have tried the following but I get a few errors:
$computers = Get-Content .\computers.txt
Get-ADPrincipalGroupMembership ForEach ($computer in $computers)
{Get-ADComputer $computer} | select-object operatingSystem, name |
Out-Gridview
Any help or guidance would be greatly appreciated. Thank you.
You could do something like this. You could put it in a script, function or whatever.
$results = New-Object -TypeName System.Collections.ArrayList
$computers = Get-Content .\computers.txt
$computers | ForEach-Object {
$ComputerObject = Get-ADComputer $_
$obj = #{
Computername = $_
OS = $ComputerObject.OperatingSystem
}
$obj.Memberships = Get-ADPrincipalGroupMembership -Identity $ComputerObject | select-object name
$results.Add($obj) | Out-Null
}
return $results
$computers = Get-Content .\computers.txt
$results = foreach ( $computer in $computers ) {
$adcomputerproperties = get-adcomputer -Identity $computer -Properties *
Get-ADPrincipalGroupMembership -Identity $adcomputerproperties.DistinguishedName
| select #{n="Computername";e={ $computer}},Name,#{n="OperatingSystem"; e={ $adcomputerproperties.OperatingSystem}} }
$results | Out-GridView
Related
I am trying to gather some information on disabled user accounts that have mailboxes. I am specifically looking for just user mailboxes not shared mailboxes.
Here is what I have so far.
$Mailboxes = Get-Mailbox | where {$_.RecipientTypeDetails -eq 'UserMailbox'}
$date = get-date -f "MMddyyyy_HHmm"
$Disabled = #()
Foreach ($Mailbox in $Mailboxes) {
if((Get-ADUser -Identity $Mailbox.SamAccountName).Enabled -eq $False){
$Disabled += Get-MailboxStatistics $Mailbox.SamAccountName | Select -Property DisplayName,TotalItemSize
}
}
$Disabled | Sort DisplayName | Export-Csv -Path "%path%\DisabledADUsersWithMailbox_$date`.csv" -NoTypeInformation
Additionally what I would like to collect is the users Title, Manager, LastlogonDate all of which can be found using Get-Aduser. I am unsure how I go about collecting the information from both cmdlets and then exporting it all to csv. I have read that I may need to create a custom object. I am struggling with setting that up in this script.
Any help would be much appreciated.
Thanks
the following lines should give you what you want, can't verify it as I have no exchange running here.
$date = get-date -f "MMddyyyy_HHmm"
$Disabled = #(
Foreach ($Mailbox in $Mailboxes) {
$adUser = get-aduser -Identity $Mailbox.SamAccountName -Properties enabled,manager,title,lastlogontimestamp
If ($adUser.Enabled -eq $False){
$mailStats = Get-MailboxStatistics $Mailbox.SamAccountName
$attrsht = [ordered]#{
displayname=$mailstats.displayname
totalitemsize=$mailStats.totalitemsize
samaccountname=$aduser.samaccountname
enabled=$aduser.enabled
manager=$aduser.manager
title=$aduser.title
lastlogontimestamp=[datetime]::FromFileTime($aduser.lastlogontimestamp)
}
new-object -TypeName psobject -Property $attrsht
}
}
)
$Disabled | Sort-Object DisplayName | Export-Csv -Path "%path%\DisabledADUsersWithMailbox_$date`.csv" -NoTypeInformation
Avoid adding elements to an array by using +=. It is slow, alternatively take a look at generic array lists.
Beginner question. We only grant access to servers by AD group. We need to report who has admin access to a list of Windows servers. My auditor likes my Server Admins script however she also wants to know the group members first, last name. I don't need to use the ADGroupMember script, if there is a better way.
If someone could point me in the right direction that will be great. It's important I understand so I can do it myself next time : )
Thanks in advance
$computers = Get-content "c:\scripts\servers.txt"
ForEach ($Line In $computers)
{
#write-host $Line
Invoke-command -ComputerName $line -ScriptBlock { net localgroup administrators} | Get-ADGroupMember -Identity "$_????what goes here????" |%{get-aduser $_.SamAccountName | select userPrincipalName } | out-file "c:\scripts\'$line'LocalAdmin.txt"
}
This script works great but does not list out group members first, lastname
$computers = Get-content "c:\scripts\servers.txt"
ForEach ($Line In $computers)
{
#write-host $Line
Invoke-command -ComputerName $line -ScriptBlock { net localgroup administrators} | out-file "c:\scripts\'$line'LocalAdmin.txt"
}
If you really need information about the users in the local Administrators group, you can use the cmdlets from the PSv5.1+ Microsoft.PowerShell.LocalAccounts module.
However, note that local accounts just have a single .FullName property, not separate first and last name ones. Also, this property may or may not be filled in:
Invoke-Command -ComputerName (Get-Content c:\scripts\servers.txt) -ScriptBlock {
Get-LocalGroupMember -Group Administrators |
Where-Object ObjectClass -eq User |
Select-Object Sid |
Get-LocalUser
} |
Sort-Object PSComputerName |
Select-Object PSComputerName, Name, FullName
If domain users are among the group's members and you do need separate first and last name information, pipe to Get-ADUser instead of to Get-LocalUser - you can distinguish users by their source (where they are defined) via the .PrincipalSource property, available on the output objects from Get-LocalGroupMember from Window 10 / Windows Server 2016.
An alternative to mklement0's helpful answer, somewhat old school, using [adsi]:
$servers = Get-Content c:\scripts\servers.txt
Invoke-Command -ComputerName $servers -ScriptBlock {
$adsi = [adsi]"WinNT://$env:COMPUTERNAME,computer"
$adsi.PSBase.Children.Find('Administrators').PSBase.Invoke('members') |
ForEach-Object {
$Name = $_.GetType().InvokeMember('Name','GetProperty',$null,$_,$null)
$class = $_.GetType().InvokeMember('Class','GetProperty',$null,$_,$null)
$adspath = $_.GetType().InvokeMember('ADSPath','GetProperty',$null,$_,$null)
$sid = [System.Security.Principal.SecurityIdentifier]::new(
$_.GetType().InvokeMember('objectsid','GetProperty',$null,$_,$null),0
).Value
[pscustomobject]#{
Name = $Name
Class = $Class
Path = $adspath -replace '^WinNT://'
SecurityIdentifier = $sid
}
} | Sort-Object Class -Descending
} | Where-Object Class -EQ User
I am missing something fundamental in PowerShell.
I have a script that generates two collections, computer names with version details of a specific application and a separate user name list that is taken from the computer names list because the user names are in the computer names, for example a computer name is:
XXXXXX02jbloggs
The owner of this computer is jbloggs and jbloggs is a valid AD object which has a full name of joe blogs.
The ultimate objective of the script is to produce a report with computer names, owner SamAccountName, full name and application details, which the script will specifically check for.
For example,
what version(s) of Adobe Reader exist on this range of machines
So far I have:
$ErrorActionPreference = "SilentlyContinue"
$Computers = Get-ADComputer -Server BlahBlah.com -Filter {name -like "XXXXXX02*"} |
Select-Object -ExpandProperty Name
$Users = $Computers -Replace '\D*\d*(\w*)', '$1'
$Results = foreach ($Computer in $Computers) {
Get-CimInstance -ComputerName $Computer -ClassName Win32_Product |
Where-Object{$_.Name -like "*Adobe Reader*"} |
Select-Object PSComputerName, Name, Version, InstallDate
}
$FullNames = ForEach ($user in $Users) {
Get-ADUser -Server BlahBlah.com -Identity $User -Properties * |
Select-Object -ExpandProperty Name
}
$Results gets me a list of computer names, Adobe Reader xxx, the version and install date.
$FullNames gets me a list of the full names based on their user IDs
I do not know how to construct the script so it produces Full Name, User Name, Computer Name, Application Name and Install Date.
This is why I say I am missing something fundamental in PowerShell, I have been looking at custom objects, nested loops and other ideas but to no avail. Really looking for some advice on this type of problem as I several similar examples I need to accomplish.
Any advice would be greatly appreciated.
Get the single current user inside the foreach($computer in $Computers) instead of creating two separate foreach.
Add a calculated property to the select to include FullName in
$Result
$ErrorActionPreference = "SilentlyContinue"
$Computers = Get-ADComputer -Server BlahBlah.com -Filter {name -like "XXXXXX02*"} |
Select-Object -ExpandProperty Name
$Results = foreach ($Computer in $Computers) {
$User = $Computer -Replace '\D*\d*(\w*)', '$1'
$FullName = (Get-ADUser -Server BlahBlah.com -Identity $User -Properties *).Name
Get-CimInstance -ComputerName $Computer -ClassName Win32_Product |
Where-Object{$_.Name -like "*Adobe Reader*"} |
Select-Object PSComputerName, Name, Version, InstallDate,#{n='FullName';e=#{$FullName}}
}
Would anybody have any suggestions? I need to generate a list of users and the computers they're logging into, from Active Directory. I'm hoping to get something like this:
Username Hostname
user.lastname ComputerA1
So far, I've gotten:
Enter-PSSession Import-Module ActiveDirectory Get-ADComputer
-Filter * -Properties Name Get-ADuser -filter * -Properties * | export-csv '\\\AD_UserLists.csv'
This works, kinda. I can generate a list of computers from AD and I can generate a list of ADUsers (albeit with ALL the users information). Unfortunately, I can't generate the data into a single CSV.
Suggestions/Advice????
Thanx,
David
Here is a way to get what you want. You will have to run this against AD-Computer objects when the machines are online, and catch the names of the computers you could not reach. Something like this...
#grab the DN of the OU where your computer objects are located...
$OU = ("OU=Computers,DC=domain,DC=com")
#put your filtered results in $computers (I filtered for Enabled objects)...
$computers = #()
ForEach ($O in $OU) {
$computers += Get-ADComputer -SearchBase $O -filter 'Enabled -eq "True"' -Properties CN,distinguishedname,lastLogonTimeStamp | Select-Object CN,distinguishedname,lastLogonTimeStamp
}
#instantiate some arrays to catch your results
#collected user info
$userInfo = #()
#computers you cannot ping
$offline = #()
#computers you can ping but cannot establish WinRM connection
$winRmIssue = #()
#iterate over $computers list to get user info on each...
ForEach ($computer in $computers) {
#filter out System account SIDs
$WQLFilter = "NOT SID = 'S-1-5-18' AND NOT SID = 'S-1-5-19' AND NOT SID = 'S-1-5-20'"
$WQLFilter = $WQLFilter + " AND NOT SID = `'$FilterSID`'"
#set number of login events to grab
$newest = 20
#attempt to ping computer once by name. return 'true' is success...
if (Test-Connection -ComputerName $computer.CN -Count 1 -ErrorAction Stop -Quiet) {
#if ping is true, try to get some info...
Try {
#currently logged in user...
$user = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $computer.CN | select -ExpandProperty username
#the most commonly logged in user, based on the past 20 log-ins...
$UserProperty = #{n="User";e={((New-Object System.Security.Principal.SecurityIdentifier $_.ReplacementStrings[1]).Translate([System.Security.Principal.NTAccount])).ToString()}}
$logs = Get-EventLog System -Source Microsoft-Windows-Winlogon -ComputerName $computer.CN -newest $newest | select $UserProperty
$freqent = $logs | Group User | Sort-Object Count | Select -First 1 | Select-Object -ExpandProperty Name
}
#catch any connection issues...
Catch {
$cantInvoke = [pscustomobject][ordered]#{
'Computer' = $computer.CN
'Message' = "Could not Invoke-Command. Probably a WinRM issue."
}
$winRMIssue += $cantInvoke
}
#custom psobject of gathered user info...
$userInfoObj = New-Object psobject -Property ([ordered]#{
'Computer' = $computer.CN
'LoggedInUser' = $user
'mostCommonUser' = $frequent
})
$userInfo += $userInfoObj
}
#if you could not ping the computer, gather that info here in a custom object...
else {
$noPing = [pscustomobject][ordered]#{
'Computer' = $computer.CN
'DN' = $computer.distinguishedname
'lastLogonDate' = [datetime]::FromFileTime($computer.lastLogonTimeStamp).toShortDateString()
}
$offline += $noPing
}
#then kick out the results to csv
$userInfo | Sort-Object Computer | export-csv -Path c:\path\file.csv -NoTypeInformation
$offline | Sort-Object lastLogonDate | export-csv -Path c:\path.file2csv -NoTypeInformation
$winRmIssue | Sort-Object Computer | export-csv -Path c:\path\file3.csv -NoTypeInformation
You could use the wmi function
Get-WmiObject -Class Win32_ComputerSystem -ComputerName "computersname" | Select-Object Name,Username
I need to generate a list of users and the computers they're logging into, from Active Directory.
This information is not stored in Active Directory. You may be able to retrieve this information with Active Directory auditing. Otherwise, you'll need to poll each individual workstation.
I've been trying to work through this for quite some time. My ultimate goal is to get the exported report as a single csv sheet. However, I've been highly unsuccessful. I then broke it down to export 2 sheets that I can just merge, however, CIM is not playing nice with that at all. Then my other issue came with not calling from my list properly.
$ComputerList = "C:\ps_test\pclastlogon.txt"
$LogPath = "C:\ps_test\Logs"
$LogTime = Get-Date -Format s | foreach {$_ -replace ":", "-"}
$CsvLogonPath = $LogPath+'\RebootStatus-'+$LogTime+'-Logon.csv'
$CsvBootPath = $LogPath+'\RebootStatus-'+$LogTime+'-LastBoot.csv'
Import-Module ActiveDirectory
IF ( -Not (Test-Path -Path $LogPath)) {New-Item -Path $LogPath -ItemType Directory}
$Computers = Get-Content $ComputerList
Foreach ($Computers in $ComputerList) {
Get-ADComputer -Identity $Computers -Properties * -Filter * | Select-Object cn,LastLogonDate,#{LABEL="Last Logon";EXPRESSION={[DateTime]::FromFileTime($_.LastLogon)}} | Export-Csv -Path $CsvLogonPath
}
Foreach ($Computers in $ComputerList) {
Get-CimInstance Win32_OperatingSystem -ComputerName $Computers | Select csname,LastBootUpTime | Export-Csv -Path $CsvBootPath
}
Can someone please point me in the right direction? Thanks in advance.
Not to use -filter * -Properties *, its too expensive. Mention the required Properties in -Properties and if you are mentioning -Identity, -filter * is not necessarily required.
Wrap Get-ADComputer and Get-CimInstance in a single foreach and create a CustomObject then export to CSV.
[Not Tested]
Fore example:
$AllDetails = Foreach ($Computers in $ComputerList) {
$DetailsfromAD = Get-ADComputer -Identity $Computers -Properties cn,LastLogonDate,LastLogon | Select-Object cn,LastLogonDate,#{LABEL="Last Logon";EXPRESSION={[DateTime]::FromFileTime($_.LastLogon)}}
$DetailsFromCIM = Get-CimInstance Win32_OperatingSystem -ComputerName $Computers | Select csname,LastBootUpTime
$PropertyHash = #{
CN = $DetailsfromAD.CN
LastLogonDate = $DetailsfromAD.LastLogonDate
'Last Logon' = $DetailsfromAD.'Last Logon'
csname = $DetailsFromCIM.csname
LastBootUpTime = $DetailsFromCIM.LastBootUpTime
}
New-Object -TypeName PSObject -Property $PropertyHash
}
Export $AllDetails to a CSV file
Just a guess here but after piping I think you need to for-each your command list. Something like
Get-ADComputer -Identity $Computers -Properties * -Filter * | % { Select-Object cn,LastLogonDate,#{LABEL="Last Logon";EXPRESSION={[DateTime]::FromFileTime($_.LastLogon)}} | Export-Csv -Path $CsvLogonPath }
But then you will need to do something to append each result instead of just having the last one in $CSvLogonPath
A general approach to join two object lists that result from a single source list:
Add the computer name ($Computers) from the original computer list ($ComputerList) as a primary key in both object lists using #{Label="ComputerName"; Expression={$Computers}}:
$ADComputers = Foreach ($Computers in $ComputerList) {
Get-ADComputer -Identity $Computers -Properties * -Filter * | Select-Object #{Label="ComputerName"; Expression={$Computers}},cn,LastLogonDate,#{LABEL="Last Logon";EXPRESSION={[DateTime]::FromFileTime($_.LastLogon)}}
}
$CimInstances = Foreach ($Computers in $ComputerList) {
Get-CimInstance Win32_OperatingSystem -ComputerName $Computers | Select #{Label="ComputerName"; Expression={$Computers}},csname,LastBootUpTime
}
Use the Join-Object function to join the object lists on the ComputerName:
$ADComputers | Join $CimInstances -On ComputerName | Export-Csv -Path $CsvBootPath
You might consider to go easy on this and forget about the primary key and just join the two tables based on the their index:
$ADComputers | Join $CimInstances -Using {$LeftIndex -eq $RightIndex}
But I recommend against this because if one of your tables is missing a record (e.g. because it doesn't exist the database), the indexes will likely be incorrect aligned.