powershell active directory excel report - powershell

I have those two scripts
$Path = 'C:\Users\akouyoumjian\Desktop\Report4.csv'
Get-ADUser -Filter {enabled -eq $true} -Properties LastLogonTimeStamp |
Select-Object Name,#{Name="Stamp"; Expression={[DateTime]::FromFileTime($_.lastLogonTimestamp).ToString('yyyy-MM-dd_hh:mm:ss')}} | Export-Csv -Path $Path –notypeinformation
and this one:
Get-ADComputer -Filter {(OperatingSystem -like "windows 7") -and (Enabled -eq "True")} -Properties OperatingSystem | Sort Name | select -Unique OperatingSystem
I would like to merge those into one file
Thanks

would this answer found here work: https://stackoverflow.com/a/27893253/10542366
This will append all the files together reading them one at a time:
get-childItem "YOUR_DIRECTORY\*.txt"
| foreach {[System.IO.File]::AppendAllText
("YOUR_DESTINATION_FILE", [System.IO.File]::ReadAllText($_.FullName))}
This one will place a new line at the end of each file entry if you need it:
get-childItem "YOUR_DIRECTORY\*.txt" | foreach
{[System.IO.File]::AppendAllText("YOUR_DESTINATION_FILE",
[System.IO.File]::ReadAllText($_.FullName) + [System.Environment]::NewLine)}
Skipping the first line:
$getFirstLine = $true
get-childItem "YOUR_DIRECTORY\*.txt" | foreach {
$filePath = $_
$lines = $lines = Get-Content $filePath
$linesToWrite = switch($getFirstLine) {
$true {$lines}
$false {$lines | Select -Skip 1}
}
$getFirstLine = $false
Add-Content "YOUR_DESTINATION_FILE" $linesToWrite
}

Related

Filter file "yyyy-MM-dd_HH-mm-ss_Computername_Username_File.json" by Computername/Username

I have a folder containing text-files with a standardized naming-scheme like:
2021-03-16_21-25-55_Client1_Edward.Hall_ServerResponse.json
2021-03-16_21-25-33_Client2_Eloise.Glover_ServerResponse.json
2021-03-16_21-17-38_Client3_Millie.Walsh_ServerResponse.json
2021-03-16_21-17-30_Client4_Lilly.Morton_ServerResponse.json
2021-03-16_21-15-45_Client5_Tia.Curtis_ServerResponse.json
2021-03-16_21-15-23_Client1_Edward.Hall_ServerResponse.json
2021-03-16_21-15-10_Client1_Lilly.Morton_ServerResponse.json
2021-03-16_21-15-03_Client2_Eloise.Glover_ServerResponse.json
2021-03-16_21-12-14_Client2_Eloise.Glover_ServerResponse.json
2021-03-16_21-11-25_Client3_Administrator_ServerResponse.json
I want to filter the files and retrieve the latest file (LastWriteTime) of a specific Computername-/Username-combination. Therefore I want to use a code like this:
# $env:COMPUTERNAME = "Client1"
# $env:USERNAME = "Edward.Hall"
$MyFolder = "C:\MyFolder"
Get-ChildItem -Path $MyFolder -File -ErrorAction SilentlyContinue | Where-Object {
$_.Extension -eq ".json" -and $_.COMPUTERNAME -eq $env:COMPUTERNAME -and $_.USERNAME -eq $env:USERNAME
} | Sort-Object -Descending -Property LastWriteTime | Select-Object -First 1
Of course the part -and $_.COMPUTERNAME -eq $env:COMPUTERNAME -and $_.USERNAME -eq $env:USERNAME is NOT working and should only show up the direction to what I imagine.
In the example above the result should be the file "2021-03-16_21-25-55_Client1_Edward.Hall_ServerResponse.json".
I was thinking of using -match, but it should be a exact match -eq.
Could you please help me to find a solution for this?
Thank you very much!
As long as you can count on the name format always conforming to that standard you can just split up the name strings for your required sections:
# $env:COMPUTERNAME = "Client1"
# $env:USERNAME = "Edward.Hall"
$MyFolder = "C:\MyFolder"
Get-ChildItem -Path $MyFolder -File -ErrorAction SilentlyContinue | Where-Object {
($_.Extension -eq ".json") -and ($_.Name.Split('_')[2] -eq $env:COMPUTERNAME) -and ($_.Name.Split('_')[3] -match $env:USERNAME)
} | Sort-Object -Descending -Property LastWriteTime | Select-Object -First 1

Getting effective user Permissions for many directories

Usually $Plist would be an array but for example we take just one directory.
My problem is I can't use the $ids var. Somehow I cant read out the data and can't bypass it to:
Get-ADGroup -Identity $id -Properties member | Select-Object -ExpandProperty member
I need the usernames per directory with their group names.
Like : Path GroupName UserList
Can someone help? Maybe tweak my code or make something similar :)
$plist = "\\Server\Share"
$FList = foreach($dir in $Plist)
{
Resolve-Path -Path $dir
Get-Acl -Path $dir -Filter Access | Select-Object -ExpandProperty Access | Where-Object {$_.IdentityReference -like "Domain\*"} | Select-Object IdentityReference
Get-Item $dir | select FullName
}
$Flist | ft FullName, IdentityReference
$identity = $Flist.IdentityReference | out-string
$ids = foreach($ident in $identity)
{
$ident = $ident.Replace("Domain\","")
$ident
}
foreach($id in $ids)
{
$id
Get-ADGroup -Identity $id -Properties member | Select-Object -ExpandProperty member
}
Do not use ft (Format-Table) or Out-String on values that you may ned later in your script.
$ids = foreach($ident in $Flist.IdentityReference){
"$ident".Replace('Domain\','')
}
You could also strip the domain prefix from all the user names in one go with the -replace operator:
foreach($id in $flist.IdentityReference.Value -replace 'Domain\\')
{
Get-ADGroup $id -Properties member | Select-Object -ExpandProperty member
}
The Final Script is this, for people who might need something similar. So you can read out the effective permissions and show the group member of permission granted groups.
$ErrorActionPreference = "SilentlyContinue"
$Path = "\\Server\Share\Logs\"
$Log = $Path + "Effective_Permissions" + ".log"
$PPath = Read-Host "Enter Path to scan"
$plist = Get-Childitem -Path $PPath -Recurse | ?{ $_.PSIsContainer } | Select-Object FullName
foreach($Dir in $PList)
{
$Dir = $Dir -replace "#{FullName=", "" -replace "}"
Resolve-Path -Path $Dir
Write-Output "`n" | Out-File $log -append
Write-Output "#######################################################################" | Out-File $Log -append
Get-Item $Dir | select FullName | Out-File $Log -append
$AclList = Get-Acl -Path $Dir -Filter Access | Select-Object -ExpandProperty Access | Where-Object {$_.IdentityReference -like "Domain\*"} | Select-Object IdentityReference
Get-Acl -Path $dir -Filter Access | Select-Object -ExpandProperty Access | Where-Object {$_.IdentityReference -like "Domain\*"} | Out-File $Log -append
foreach($Id in $AclList.IdentityReference.Value -replace 'Domain\\')
{
$ADGroup = Get-ADGroup $Id -Properties member | Select-Object -ExpandProperty member
Write-Output "`n" | Out-File $Log -append
Write-Output "Member of $Id `n
---------------------------------" | Out-File $Log -append
foreach ($Object in $ADGroup)
{
$Group = Get-ADUser -filter * -SearchBase "$Object"
if($Group -ne $null)
{
$GrName = $Group.Name
Write-Output "$GrName" | Out-File $Log -append
}
}
}
Clear-Variable Object, Group, ADGroup, ACLList, GRName, Id
}

Powershell Export-CSV

I'm just having problems trying to export the following to a CSV, I've tried putting the Export-CSV within the Foreach-Object loop to no avail.
I want to put the server name $server in the first column and the description $description in the second.
In an earlier version, I was able to make a text file using Out-File -append .\outa.txt -InputObject $_.Name,$description but the formatting did not work well.
$server = Get-ADComputer -Filter {OperatingSystem -Like "*Server*" -and Name -Notlike "*DOM*"}
$server | ForEach-Object {
$Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine',$_.Name)
$RegKey = $Reg.OpenSubKey("SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters")
$description = $RegKey.GetValue("srvcomment")
} | Export-Csv .\out1.csv
A ForEach as oppose to ForEach-Object:
$server = Get-ADComputer -Filter {OperatingSystem -Like "*Server*" -and Name -Notlike "*DOM*"}
foreach($s in $server){
# replaced $_ with $s
$Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine',$s.Name)
$RegKey= $Reg.OpenSubKey("SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters")
$description = $RegKey.GetValue("srvcomment")
# casting as array is required to use +=
# disclaimer: the array is destroyed and rebuilt on each run.
[array]$myData += New-Object psobject -Property #{
Server = $s.Name
Description = $description
}
}
# If you want a CSV without the top info line, use the notypeinfo switch
# Select-Object gives you the column order you want.
$myData | Select-Object Server,Description | Export-Csv .\out1.csv -NoTypeInformation
Edit - comment answer
It is possible to do it without creating an array and from inside the loop, but an object is required by Export-Csv AFAIK.
ForEach-Object:
$server = Get-ADComputer -Filter {OperatingSystem -Like "*Server*" -and Name -Notlike "*DOM*"}
$server | ForEach-Object {
$Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine',$_.Name)
$RegKey = $Reg.OpenSubKey("SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters")
New-object psobject -Property #{Server=$_.Name;Description=$RegKey.GetValue("srvcomment")} | Export-Csv .\out1.csv -NoTypeInformation
}
ForEach:
$server = Get-ADComputer -Filter {OperatingSystem -Like "*Server*" -and Name -Notlike "*DOM*"}
foreach($s in $server){
$Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine',$s.Name)
$RegKey= $Reg.OpenSubKey("SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters")
New-object psobject -Property #{Server=$s.Name;Description=$RegKey.GetValue("srvcomment")} | Export-Csv .\out1.csv -NoTypeInformation
}
If you have problems with the values, brackets/subexpressions can help:
New-object psobject -Property #{Server=($_.Name);Description=($RegKey.GetValue("srvcomment"))} | Export-Csv .\out1.csv -NoTypeInformation
New-object psobject -Property #{Server=$($_.Name);Description=$($RegKey.GetValue("srvcomment"))} | Export-Csv .\out1.csv -NoTypeInformation
Your ForEach-Object only contains statements (variable assignments). It's not returning anything. You need to return something, otherwise you're passing an empty pipeline to Export-CSV.
I'm guessing that, instead of setting variables called $Reg, $RegKey, and $description (and then never using their values), what you actually want to do is create columns in the CSV called Reg, RegKey, and description. In that case, you want to yield a [PSCustomObject] (with those properties added to it) each time through the loop.
$server = Get-ADComputer -Filter {OperatingSystem -Like "*Server*" -and Name -Notlike "*DOM*"}
$server | ForEach-Object {
[PSCustomObject] #{
Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine',$_.Name)
RegKey = $Reg.OpenSubKey("SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters")
description = $RegKey.GetValue("srvcomment")
}
} | Export-Csv .\out1.csv

Get-Acl list only Users

I need a list of all directories (recursive) which have user-permissions registered (not user-groups).
Something like:
Get-ChildItem -Recurse c:\scripte | Get-Acl |
Where-Object -FilterScript {$_.objectclass -eq 'user'}
I think there must be some Get-ADUser stuff?
Something like this should do, assuming that you have PowerShell v3 or newer:
Get-ChildItem c:\scripte -Recurse -Directory | Where-Object {
(Get-Acl $_.FullName).Access.IdentityReference -match "^$env:USERDOMAIN\\" -replace '^.*\\' |
ForEach-Object { Get-ADUser -Filter "SamAccountName -eq $_" }
}
If you're stuck with PowerShell v2 the statement gets a little more elaborate:
Get-ChildItem c:\scripte -Recurse | Where-Object {
$_.PSIsContainer -and
(Get-Acl $_.FullName | Select-Object -Expand Access |
Select-Object -Expand IdentityReference) -match "^$env:USERDOMAIN\\" -replace '^.*\\' |
ForEach-Object { Get-ADUser -Filter "SamAccountName -eq $_" }
}
here ya go
{
param(
[parameter(mandatory=$true)]$Path
)
$IDs = (get-acl $Path).Access | Select IdentityReference,FileSystemRights
foreach ($ID in $IDs)
{
$thisUser = ($ID.IdentityReference).ToString()
$Rights = ($ID.FileSystemRights).ToString()
$User = $thisUser.split("\")[1]
$Object = Get-ADobject -LDAPFilter "(samAccountName=$user)" | Select ObjectClass
[pscustomObject]#{
Type = $Object.ObjectClass
samAccountName = $User
Rights = $Rights
}
}
}

Get group member names from Get-Acl and Append to CSV

I need to extract all the members of a group and then format that into Names, so I only get the Full Names like "Don Joe" is member of my-domain\UNCShareDrive
I need that to appear in my CSV after I have exported the ACL lists.
As an example:
Path FileSystemRights AccessControlType IdentityReference
---- ---------------- ----------------- -----------------
Microsoft.PowerShell.Core\FileSystem::\\fileshare\management\DK FullControl Allow MY-DOMAIN\Drev Management
Microsoft.PowerShell.Core\FileSystem::\\fileshare\management\ FullControl Allow BUILTIN\Administratorer
Microsoft.PowerShell.Core\FileSystem::\\fileshare\management\ FullControl Allow MY-DOMAIN\Drev Management
Microsoft.PowerShell.Core\FileSystem::\\fileshare\management\ FullControl Allow BUILTIN\Administratorer
**These persons has access to the drive:**
**Finding group: MY-DOMAIN\Administrators**
Name SamAccountName Mail
---- -------------- ----
Administrator Administrator Administrator#my-domain.dk
This is what I have so far done in Powershell:
$Searching = Get-ADGroup -Filter * -SearchBase "DC=my-domain,DC=local"
$mypath = "U:\mytest.csv"
if((Test-Path -Path "U:\mytest.csv" -pathtype Container) -eq $True){
Write-Host -ForegroundColor red "We found a file: $mypath --> REMOVING!`r`n"
Remove-Item $mypath -Force
}
$ShareName = "\\\sharename\D$"
$shares = Get-Childitem -path $ShareName |
Where-Object {$_.PSIsContainer} |
Get-ACL |
Select-Object Path -ExpandProperty Access |
Select Path, FileSystemRights,AccessControlType,IdentityReference |
export-csv $mypath -Delimiter ';' -NoTypeInformation -Encoding UTF8
$foldertotal = 0
Add-Content $mypath ""
Add-Content $mypath ""
Add-Content $mypath "Disse personer har adgang til share navnet"
Add-Content $mypath ""
Add-Content $mypath ""
$myLoop = ''
foreach ($testLoop in $myLoop) {
$Group = Get-ADGroup -Filter * -SearchBase "DC=my-domain,DC=local" -Properties IdentityReference |
Select-Object Name # Need only groups in $Shares - who are displayed
$myLoop += Write-Host -ForegroundColor Yellow "Finding group: $($Group.name).....`n"
$myLoop += ForEach ($Group in $share) {
Get-ADGroupMember -identity $($Group.name) -recursive |
Get-ADUser -Properties Name,SamAccountName,Mail |
Select-Object Name,SamAccountName,Mail
}
$testLoop | Out-File -filePath $mypath -append -encoding utf8
}
Write-Host -ForegroundColor Cyan "$($Group.name) is now exported to: $mypath`n"
I have also a hard time to filter out only the share path:
$shares.Replace('Microsoft.PowerShell.Core\FileSystem::', ' ') |
Out-File -filePath $mypath -append -encoding utf8
How come that this thing Works when I use User Input and not just automatically loop through it without the console prompt:
$Searching = Get-ADGroup -Filter * -SearchBase "DC=MY-DOMAIN,DC=local"
$mypath = "U:\mytest.csv"
$networkPath = "\\ShareName\D$"
$acl = Get-acl -path $networkPath
if((Test-Path -Path "U:\mytest.csv" -pathtype Container) -eq $True){
Write-Host -ForegroundColor red "We found a file: $mypath --> REMOVING!`r`n"
Remove-Item $mypath -Force
}
Write-Host -ForegroundColor Yellow "Eksempel på share: "`r`n\\ShareName\D$`r`n\\ShareTwo\\E$`r`n\\ShareName\management`r`n""
$ShareName = Read-host "Hvilket sharenavn vil du finde Access Control List fra?"
if($ShareName -eq "1"){
$Sharename = "\\ShareName\D$"
}
if($ShareName -eq "2"){
$Sharename = "\\ShareTwo\\E$"
}
if($ShareName -eq "3"){
$Sharename = "\\ShareName\management"
}
Get-Childitem -path $ShareName |
Where-Object {$_.PSIsContainer} |
Get-ACL |
Select-Object Path -ExpandProperty Access |
Select Path, FileSystemRights,AccessControlType,IdentityReference |
FT -AutoSize |
Out-File -Encoding utf8 $mypath
Add-Content $mypath ""
Add-Content $mypath ""
Add-Content $mypath "Disse personer har adgang til share navnet"
Add-Content $mypath ""
$users = get-aduser -Filter {Name -Like "*"} -Searchbase "dc=MY-DOMAIN,dc=local" -Properties MemberOf |
Where-Object { $_.Enabled -eq 'True' }
Write-Host -ForegroundColor red "Example: Drev Management`r`n"
$myGroups = Read-Host "Hvilken Gruppe vil du bruge?"
if($myGroups -eq "1"){
$myGroups = " Drev Management"
}
$Groups = Get-ADGroup -filter {Name -like $myGroups} | Select-Object Name
Add-Content $mypath "Finding group: $($group.name)"
Write-Host -ForegroundColor Yellow "Finding group: $($Group.name).....`n"
Add-Content -Path $mypath $result
ForEach ($Group in $Groups) {
Get-ADGroupMember -identity $($Group.name) -recursive |
Get-ADUser -Properties Name,SamAccountName,Mail |
Select-Object Name,SamAccountName,Mail |
FT -AutoSize |
Out-File -Append -encoding utf8 $mypath
}
Write-Host -ForegroundColor Cyan "$($Group.name) is now exported to: $mypath`n"
Your second code sample works, because it doesn't make the same mistakes as the first one.
$myLoop = ''
foreach ($testLoop in $myLoop) {
$Group = Get-ADGroup -Filter * ...
$myLoop += Write-Host ...
$myLoop += ForEach ($Group in $share) {
Get-ADGroupMember ...
}
$testLoop | Out-File -filePath $mypath -append -encoding utf8
}
You make $myLoop an empty string, then iterate over each element of $myLoop (one empty string), so you get a single loop cycle, no matter what you append to $myLoop inside the loop.
Instead of the group members you write the content of $testLoop (an empty string) to the output file.
You read AD groups into the variable $Group, and then overwrite its content when you use $Group as the loop variable in foreach ($Group in $share).
$share is emtpy, because it's never initialized anywhere. Even $shares is empty, because when you write the ACL information to the CSV, no output is left that could be assigned to the variable.
And as a side-note: you can't append Write-Host output to anything, because the cmdlet writes to the host process (i.e. the console), not a stream that could be captured or redirected.
You need to capture the ACL information in $shares before writing it to a file:
$shares = Get-Childitem -Path $ShareName |
Where-Object {$_.PSIsContainer} |
Get-ACL |
Select-Object Path -ExpandProperty Access |
Select Path, FileSystemRights,AccessControlType,IdentityReference
$shares | Export-Csv $mypath -Delimiter ';' -NoTypeInformation -Encoding UTF8
Then you can determine the members of the groups having access to shares like this:
$shares | Select-Object -Expand IdentityReference |
Select-Object -Expand Value |
ForEach-Object {
$name = $_ -replace '^DOMAIN\\' # <-- replace with actual domain name
Get-ADObject -Filter { Name -eq $name }
} |
Where-Object { $_.ObjectClass -eq 'group' } |
Get-ADGroupMember |
Get-ADUser -Properties * |
Select-Object Name, SamAccountName, Mail |
Out-File $mypath -Append -Encoding UTF8
Note that this will not resolve nested groups, and also won't distinguish between shares.
If you want to store both the group name and its members you need to add a loop to the pipeline:
$shares | Select-Object -Expand IdentityReference |
Select-Object -Expand Value |
ForEach-Object {
$name = $_ -replace '^DOMAIN\\' # <-- replace with actual domain name
Get-ADObject -Filter { Name -eq $name }
} |
Where-Object { $_.ObjectClass -eq 'group' } |
ForEach-Object {
$_
Get-ADGroupMember -Identity $_ |
Get-ADUser -Properties * |
Select-Object Name, SamAccountName, Mail
} |
Out-File $mypath -Append -Encoding UTF8