Get specific info on domain computers from AD OUs - powershell

I'm trying to Get the Name, Manufacturer, and model of computers so i can distinguish what computers are out of warranty in AD.
I'm trying to do this by getting the computer names and putting there info into the corresponding .csv file but this fails and puts 1 ou to multiple .csv files and then moves to the second ou and does the same thing?
$myMultiArray = #(("OU=Domain Controllers,DC=FABRIKAM,DC=COM"),
("OU=Computers,DC=FABRIKAM,DC=COM"))
$myFileArray = #(("‪D:\VS-Code\Powershell\AD_Computer_Management\OUs\Domain
Controllers.csv"),("‪D:\VS-
Code\Powershell\AD_Computer_Management\OUs\Computers.csv"))
foreach ($MultiOU in $myMultiArray) {
Get-ADComputer -Filter * -SearchBase $MultiOU -SearchScope 2 | Select-object Name | Out-File -FilePath "D:\VS-Code\Powershell\AD_Computer_Management\OUs\garbage.csv"
For ($i = 0; $i – $myFileArray.Length - 1; $i++) {
Write-Host $myMultiArray[$i]
[string[]]$cnArray = Get-Content -Path 'D:\VS-Code\Powershell\AD_Computer_Management\OUs\garbage.csv'
Write-Host $OU
if ($i -eq $i) {
foreach($CN in $cnArray){
Get-WmiObject -Class:Win32_ComputerSystem -ComputerName $OU | Format-List -Property Name, Manufacturer, Model | Out-File -FilePath $myFileArray[$1]
}
}
}
}
I've tried multiple variations of different loops and if statements.

I think there are two things:
Out-File -FilePath $myFileArray[$1]
Should be:
Out-File -FilePath $myFileArray[$i]
And also you might need to append:
Out-File -FilePath $myFileArray[$i] -Append

There are a couple of things wrong in your code, like $i – $myFileArray.Length, which should be $i –lt $myFileArray.Length.
Then there is Out-File -FilePath $myFileArray[$1] as Bernard Moeskops already mentioned.
Also your code seems to want to create both the Domain Controllers.csv aswell as the Computers.csv files regardless of the OU you are currently in.
Lastly, you are using Out-File to create the CSV files where for proper CSV output, you should use the Export-Csv cmdlet.
The following code should do what you want:
$myOUArray = "OU=Domain Controllers,DC=FABRIKAM,DC=COM", "OU=Computers,DC=FABRIKAM,DC=COM"
$myFilePath = "‪D:\VS-Code\Powershell\AD_Computer_Management\OUs" # just the path for the output files is needed
foreach ($OU in $myOUArray) {
# determine the file name from the OU we're in
$fileName = if ($OU -match 'OU=Domain Controllers') { 'Domain Controllers.csv' } else { 'Computers.csv'}
$filePath = Join-Path -Path $myFilePath -ChildPath $fileName
Write-Host "Getting computer info from OU '$OU'"
# get a string array of the computernames found in the OU
$computers = Get-ADComputer -Filter * -SearchBase $OU -SearchScope Subtree | Select-Object -ExpandProperty Name
# loop through this array to get the properties you want for
# each computer and store that as objects in the $result variable
$result = foreach($machine in $computers){
Get-WmiObject -Class:Win32_ComputerSystem -ComputerName $machine | Select-Object -Property Name, Manufacturer, Model
}
Write-Host "Creating file '$filePath'"
# save the CSV file to disk
$result | Export-Csv -Path $filePath -NoTypeInformation -Force
}

Related

powershell better way to test if both directories exists or one only on all pc's from domain and output to csv

could you please help me to correct this script (gathered by pieces from internet) or better change logic how it should work (not working currently). The goal is to get pc's where only one folder exist (oracle11) and not both (11+12) and export it to csv. Oracle is a real pain in the ....
Thank you in advance for your advice.
Import-Module ActiveDirectory
$computers = Get-ADComputer -Filter * -Properties * | Select -Property Name
$output = #()
#$computers = get-adcomputer -filter * | Select-Object -Expand Name | foreach-object {
Foreach ($Computer in $computers){
if ( (test-path "\\$Computer\C$\oracle\product\11.2.0\" ) -and !( test-path "\\$Computer\C$\oracle\product\12.2.0" )) {
$output += $Computer
}
}
$output | Export-Csv -NoTypeInformation -Path c:\temp\test.csv
The problem is that the path strings you construct inside the loop are not as you expect.
When you pipe the output from Get-ADComputer to Select-Object -Property Name, it creates a new object with a single property Name for each input object.
When you then implicitly convert one of these objects to a string, the resulting value is going to be "#{Name=Computer01}", instead of just "Computer01".
You can observe this yourself, by calling Write-Host instead of Test-Path:
Get-ADComputer -Filter * |Select-Object -Property Name |ForEach-Object {
Write-Host "\\$_\C$"
}
To extract just the value of the Name property from each ADComputer, use ForEach-Object -MemberName instead of Select-Object -Property:
$computerNames = Get-ADComputer -Filter * -Properties * | ForEach-Object -MemberName
$output = #()
foreach($ComputerName in $computerNames){
if ( (Test-Path "\\$ComputerName\C$\oracle\product\11.2.0\" ) -and !( Test-Path "\\$ComputerName\C$\oracle\product\12.2.0" )) {
$output += $ComputerName
}
}
$output | Export-Csv -NoTypeInformation -Path c:\temp\test.csv
Note that passing -Properties * to Get-ADComputer is unnecessary, the object name is always part of the default property set sent back by the Get-AD* cmdlets.

Powrshell to export list of all PCs and if they have specific application install

I currently use the following powershell script to export the list of all VMs on our network with their information and export into an excel file:
#// Set CSV file name
$uDateTime = Get-Date -f "yyyy-MM"
$uCSVFile = "C:\Servers"+$uDateTime+".csv"
#//Export out to csv file.
Get-ADComputer -filter * -Properties ipv4Address, OperatingSystem,DistinguishedName |
select-object Name, ipv4Address, OperatingSystem, #{label='OU';expression=
{$_.DistinguishedName.Split(',')[1].Split('=')[1]}} |
export-csv -path $uCSVFile
The excel content would look something like this:
I want to add another column to indicate if specific application exists on each server or not like this one
Upon googling around I see that I can utilize the Get-ItemProperty to read the registry in order to check if certain program is installed on individual VM, but I am having problem tying the code to my existing one. It gives me the same result based on the machine where this PowerShell scripts runs on instead of each VM registry individually ...
Can you help me making this script read each VM's registry
#// Set CSV file name
$uDateTime = Get-Date -f "yyyy-MM"
$uCSVFile = "C:\Servers"+$uDateTime+".csv"
#//Export out to csv file.
Get-ADComputer -filter * -Properties ipv4Address, OperatingSystem,DistinguishedName |
select-object Name, ipv4Address, OperatingSystem, #{label='OU';expression=
{$_.DistinguishedName.Split(',')[1].Split('=')[1]}},
#{label='HelloKitty Installed';expression={(Get-ItemProperty "HKLM:\Software\HelloKitty\*" | Where {
$_.Version -ne $null }) -ne $null}}|
export-csv -path $uCSVFile
To read a registry key from the computer you are targetting instead of the computer the script is currently running from, you should use the Invoke-Command cmdlet.
However, keep in mind that Get-ADComputer can also list computers that are currently off-line, so I would suggest using a ForEach-Object loop which will give you a chance to test for that first.
Something like this:
#// Set CSV file name
$uCSVFile = 'C:\Servers{0:yyyy-MM}.csv' -f (Get-Date)
#//Export out to csv file.
$result = Get-ADComputer -Filter * -Properties ipv4Address, OperatingSystem,DistinguishedName |
ForEach-Object {
if (Test-Connection -ComputerName $_.Name -Count 1 -Quiet) {
# computer is on line. If need be, add -Credential to the Invoke-Command cmdlet
# because reading the HKEY_LOCAL_MACHINE hive needs Administrator permissions.
# Also, the targetted machines must have the 'Remote Registry' service enabled.
try {
$installed = Invoke-Command -ComputerName $_.Name -ScriptBlock {
$null -ne (Get-ItemProperty "HKLM:\SOFTWARE\HelloKitty\*" |
Where-Object { $null -ne $_.Version }).Version
} -ErrorAction Stop
}
catch { $installed = "ERROR" }
}
else { $installed = "OFF-LINE" }
# output an object
$_ | Select-Object Name, ipv4Address, OperatingSystem,
#{Name = 'HelloKitty Installed'; Expression = { $installed }}
}
# now export to CSV
$result | Export-Csv -Path $uCSVFile -UseCulture -NoTypeInformation
I have added switch -UseCulture to the Export-Csv cmdlet so the delimiter character used in the csv file will be the same as your local Excel expects

Foreach loop and writing the results to a file

I'm working on a script which iterates through all users found across a domain, grabs a few credentials and then returns them in the format of an SQL INSERT statement which I want stored in a .txt file as output.
So far I've only been able to write the last user to a file however I'm able to print out in the terminal every single user. I have a feeling that I'm overwriting the .txt output file each time I iterate through my foreach loop.
Below is my code which has been sanitised:
$users = Get-ADUser -Properties uidNumber, sAMAccountName -SearchBase' OU=LiveUsers,OU=Users,OU=MyBusiness,DC=local' -Filter *
$message = ""
Set-Content -Path C:\Desktop\UIDs\currentList.txt -Value $null # ensures file is blank
foreach ($user in $users | Select-Object -Property uidNumber, sAMAccountName){
#Search in specified OU and List above for UID and name and write to a file
$message = "INSERT INTO `DataBaseNameHere`.`currentUser` (`User_id`, `User_name`) VALUES ('" + $user.uidNumber + "', '" + $user.sAMAccountName + "');" |
Out-File -FilePath C:\Desktop\UIDs\currentList.txt
}
Get-Content -Path C:\Desktop\UIDs\currentList.txt
I've tried other variations of foreach loops, Out-File and Tee-Object so far.
Assuming that the sanitized code you provided does what you want except for leaving only a single line in the output file, you need to ensure that you have either no existing output file or that it's blank, and then you add the -append switch to the Out-File cmdlet:
$users = Get-ADUser -Properties uidNumber, sAMAccountName -SearchBase 'OU=LiveUsers,OU=Users,OU=MyBusiness,DC=local' -Filter *
Set-Content -Path C:\Desktop\UIDs\CurrentList.txt -Value $null # ensures file is blank
foreach ($user in $users | Select-Object -Property uidNumber, sAMAccountName) {
$message = "INSERT INTO `databaseNameHere`.`currentUser` (`User_id`, `User_name`) VALUES ('" + $user.uidNumber + "', '" + $user.sAMAccountName + "');"
Out-File -FilePath C:\Desktop\UIDs\currentList.txt -append # -append added to not overwrite existing content.
}
See Out-File at Microsoft Docs.
The code you posted would not write anything to a file since the loop defines $message without doing anything with it, and then calls Out-File without any input.
Something like this should do what you want:
Get-ADUser ... |
Select-Object uidNumber, sAMAccountName |
ForEach-Object { "INSERT INTO `databaseNameHere`.`currentUser` (...);" } |
Out-File -FilePath C:\Desktop\UIDs\currentList.txt
Beware though, that building INSERT statements that way is vulnerable to SQL injection and should be avoided.
So, after taking elements from a few of your answers I was able to modify my code and fix the loop. I was just using the Out-File cmdlet wrong.
$users = Get-ADUser -Properties uidNumber, sAMAccountName -SearchBase 'OU=LiveUsers,OU=Users,OU=MyBusiness,DC=myCompany,DC=local' -filter *
Clear-Content -Path C:\Desktop\UIDs\CurrentList.txt
foreach ($user in $users ){
“INSERT INTO `databasename`.`currentUser` (`User_id`, `User_name`) VALUES ('"+ $user.uidNumber + "','"+ $user.sAMAccountName +"');" |
Out-File -FilePath C:\Desktop\UIDs\CurrentList.txt -Append
}

Export data based on foreach login [Powershell]

I have simple csv file with column 'logins'
logins
john
mark
maria
...
Have powershell script to check their last logontime:
Import-Module ActiveDirectory
function Get-ADUserLastLogon([string]$userName)
{
$time = 0
$user = Get-ADUser $userName | Get-ADObject -Properties lastLogon
if($user.LastLogon -gt $time)
{
$time = $user.LastLogon
}
$dt = [DateTime]::FromFileTime($time)
Write-Host $username $dt }
import-csv -Encoding UTF8 -path C:\scripts\loginy.csv | foreach {
Get-ADUserLastLogon -UserName $_.logins
}
This works fine with output
john 2018-05-10 14:11:28
mark 2018-11-29 14:26:58
maria 2018-11-02 11:14:17
...
When I try to export results it to csv file by code
$users = import-csv -Encoding UTF8 -path C:\scripts\loginy.csv
$results = #()
foreach ($_.logins in $users) {
$results += Get-ADUserLastLogon -UserName $_.logins
}
$results | Export-CSV C:\scripts\Eksporty\logowania.csv -Append -encoding "utf8"
getting error
At C:\scripts\OstatnieLogowanie.ps1:19 char:12
+ foreach ($_.logins in $users) {
+ ~
Missing 'in' after variable in foreach loop.
At C:\scripts\OstatnieLogowanie.ps1:19 char:29
+ foreach ($_.logins in $users)
}
I can't get it work over 2 hours :/
Edit: I've confused LastLogon and LastLogonTimestamp. LastLogonDate is based on LastLogonTimestamp. The differences between these properties are explained here and here. I will come back and update my answer.
You're using Write-Host to output data:
Write-Host $username $dt
This won't work. Write-Host means "write to the console screen, not to standard output." That will work just fine if you're trying to display data, but calling $x = Get-ADUserLastLogon -UserName $login will print the results to the console screen and nothing would be assigned to the $x variable. For example:
PS C:\> $x = Write-Host 0
0
PS C:\> $x
PS C:\>
See how Write-Host still wrote to the console and $x doesn't have a value?
Your function should look something like $username, $dt or Write-Output $username, $dt or return $username, $dt.
Although that's still not really going to work like you want. I would probably use a custom object (see Get-Help about_Object_Creation -ShowWindow) like this:
Import-Module ActiveDirectory
function Get-ADUserLastLogon([string]$userName) {
$user = Get-ADUser $userName -Properties LastLogonDate
[PSCustomObject]#{'Logins' = $username; 'LastLogonDate' = $user.LastLogonDate}
}
$users = import-csv -Encoding UTF8 -path C:\scripts\loginy.csv
$results = foreach ($user in $users) {
Get-ADUserLastLogon -UserName $user.logins
}
$results | Export-CSV C:\scripts\Eksporty\logowania.csv -Append -encoding "utf8"
Frankly, however, if I were doing what you're trying to do here, my actual code would look like this:
Import-Csv -Encoding -Path C:\scripts\loginy.csv |
Select-Object -ExpandProperty logins |
Get-ADUser -Properties LastLogonDate |
Select-Object #{n = 'Logins'; e = {$_.SamAccountName}}, LastLogonDate |
Export-Csv -Path C:\scripts\Eksporty\logowania.csv -Encoding UTF8 -NoTypeInformation
Select-Object -ExpandProperty logins will pass just the bare value of the logins column. Get-ADUser accepts identities from the pipeline, and it fetches the LastLogonDate for each user, as long as the SamAccountName (a default property) which is the logon name.
The next line, Select-Object #{n = 'Logins'; e = {$_.SamAccountName}}, LastLogonDate uses a calculated property (See the examples in Get-Help Select-Object -ShowWindow) to rename the SamAccountName property in a column named Logins. You could use Select-Object SamAccountName, LastLogonDate if you don't care about the column name. And the -NoTypeInformation parameter on Export-Csv just keeps it from adding that annoying "#TYPE System.Management.Automation.PSCustomObject" nonsense on the first line.
$_ is the variable for the current value in pipeline. In your second part of code, since you don't have a pipeline, hence $_ is empty and doesn't have any property/method associated with it.
What you can do is -
$users = import-csv -Encoding UTF8 -path C:\scripts\loginy.csv
foreach ($user in $users) {
Get-ADUserLastLogon -UserName $user.logins | Export-CSV C:\scripts\Eksporty\logowania.csv -Append -encoding "utf8"
}
OR
$users = import-csv -Encoding UTF8 -path C:\scripts\loginy.csv
foreach ($_ in $users) {
Get-ADUserLastLogon -UserName $_.logins | Export-CSV C:\scripts\Eksporty\logowania.csv -Append -encoding "utf8"
}
Although I would recommend not using the latter since $_ is an automatic variable $PSItem and beside you can have plenty other names for a variable which are not keywords, functions etc.
The use of += to extend an array requires creating a new instance behind the scenes in every iteration.

Work with ADComputer output in foreach loop

I want to output all hostnames within a network first with a foreach loop, in order (for example) to be able to ping them.
However with the following code I do not get any output in the console. The CSV file will be saved, but what is written in the loop will not be executed.
Does anyone know what the reason for this is and how I can solve it?
Import-Module activedirectory
Get-ADComputer -Filter * -Property * | Select Name | Export-CSV -Path $env:TEMP\ZZZEXPORTE.csv -NoTypeInformation -Encoding UTF8 | ForEach {
$computerName = $_.Name
Write-Host $computerName
Write-Host "----"
}
This occurs because Export-CSV does not output an object. Sometimes cmdlets like this have a -PassThru parameter which you can use to have an object passed along, but thats not the case with Export-CSV, they simply expect it to always be the last cmdlet in the pipeline.
You should instead do this:
$Computers = Get-ADComputer -Filter * -Property * | Select Name
$Computers | Export-CSV -Path $env:TEMP\ZZZEXPORTE.csv -NoTypeInformation -Encoding UTF8
$Computers | ForEach {
$computerName = $_.Name
Write-Host $computerName
Write-Host "----"
}
You could also do this:
Get-ADComputer -Filter * -Property * | Select Name | ForEach {
$computerName = $_.Name
Write-Host $computerName
Write-Host "----"
$_
} | Export-CSV -Path $env:TEMP\ZZZEXPORTE.csv -NoTypeInformation -Encoding UTF8
Noting that we have to add $_ to our ForEach-Object loop so that it outputs the current item to the pipeline, but that our Write-Host statements don't effect the pipeline because they are writing to the console only. To be honest though, this is a bit harder to follow for anyone else reading your code.