Check if OU exists not working properly - powershell

Wrote this small script to test if an OU exists, if exists write to console and terminate. If not exists create OU and do some other stuff. Though can't seem to understand why i cant get it working.
For some reason the output will always tell me that the OU exists, and I am pretty sure it does not. Am I doing something terribly wrong?
This is the code:
param (
[parameter(mandatory=$true)] [string] $servername
)
Import-Module ActiveDirectory
Function CheckOU {
$script:OUpath = "OU=$servername,OU=Rechtengroepen,OU=danny,dc=Doenoe,DC=com"
$Status = $false
$GetOU = Get-ADOrganizationalUnit -Identity $OUpath -ErrorAction SilentlyContinue
if ($GetOU -eq $null) {
$status = $false
Write-Host -ForegroundColor Green "$OUpath does not exist."
} else {
$Status = $true
Write-Host -ForegroundColor Red "$OUpath exists!"
}
return $Status
}
$OUStatus = CheckOU
if ($OUStatus -eq $true) {
Write-Host "$OUpath exists. Function working."
} else {
Write-Host "$OUpath does not exsist, do something."
}
Output:
Get-ADOrganizationalUnit : Directory object not found
At C:\Scripts\CreateOUgroups\createadgroups_test02.ps1:10 char:14
+ $GetOU = Get-ADOrganizationalUnit -Identity $OUpath -ErrorAction SilentlyCon ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (OU=notexistsing...c=Doenoe,DC=com:ADOrganizationalUnit) [Get-ADOrganizationalUnit], ADIdentityNotFoundException
+ FullyQualifiedErrorId : ActiveDirectoryCmdlet:Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException,Microsoft.ActiveDirectory.Management.Commands.GetADOrganizationalUnit
OU=notexistsingOU,OU=Rechtengroepen,OU=danny,dc=Doenoe,DC=com exists!
OU=notexistsingOU,OU=Rechtengroepen,OU=danny,dc=Doenoe,DC=com exists. Function working.

Using the cmdlet with the -Identity parameter causes a terminating error if the object with the given identity doesn't exist. Use -Filter to avoid this issue:
Get-ADOrganizationalUnit -Filter "distinguishedName -eq '$OUPath'"

Related

Argument Passed into ScriptBlock Doesn't Work on Last Iteration

I'm using the following script to run through all of the servers in a specified Active Directory OU and log out the specified user. This runs perfectly well for the first 35 servers but always errors out on the very last server it iterates through. The error is:
Program 'quser.exe' failed to run: Object reference not set to an instance of an object. At line:6 char:24
+ $result = (quser $userAccount)
+ ~~~~~~~~~~~~~~~~~~.
At \\path\to\script.ps1:79 char:5
+ invoke-command -ComputerName $server -ScriptBlock $scriptBlock -A ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (Program 'quser....~~~~~~~~~~~~~~.:String) [], RuntimeException
+ FullyQualifiedErrorId : Program 'quser.exe' failed to run: Object reference not set to an instance of an object.At line:6 char:24
+ $result = (quser $userAccount)
+ ~~~~~~~~~~~~~~~~~~.
My reading of the error is that it thinks $userAccount has no value. Is that correct and, if so, can anyone point at what I'm missing? Thank you in advance!
Write-Host " "
Write-Host "This script will log out all active sessions for the specified user. Proceed with caution." -ForegroundColor Black -BackgroundColor Yellow
Write-Host " "
$servers = [System.Collections.ArrayList]::new()
foreach ($server in (Get-ADComputer -SearchBase "OU=FictionalDepartment,DC=Company,DC=net" -Filter "OperatingSystem -like 'Windows Server*'" -Properties Name | select -ExpandProperty name))
{
$servers.add($server) | Out-Null
}
$servers.Sort()
$userAccount = Read-Host "Enter account to log out"
Write-Host " "
foreach ($server in $servers)
{
$scriptBlock = {
param($userAccount)
$ErrorActionPreference = 'Stop'
try
{
$result = (quser $userAccount)
$session = ((quser $userAccount)[1] -split "\s+")[2]
logoff $session
Write-Host " The user was logged into session #$session. They have been LOGGED OFF." -ForegroundColor Yellow
}
catch
{
if ($_.Exception.Message -match 'No user exists')
{
Write-Host " User is not logged in." -ForegroundColor Green
}
else
{
throw $_.Exception.Message
}
}
}
Write-Host "$server"
Invoke-Command -ComputerName $server -ScriptBlock $scriptBlock -ArgumentList $userAccount
$session = $null
}
Based on feedback, I modified the script so that it no longer uses Invoke-Command, but parses the active sessions by running quser <user> /SERVER:<server> as follows:
Write-Host "Will log specified user out of all servers..." -ForegroundColor Black -BackgroundColor Yellow
Write-Host " "
$servers = [System.Collections.ArrayList]::new()
foreach ($server in (Get-ADComputer -SearchBase "OU=Fictional,DC=Company,DC=net" -Filter "OperatingSystem -like 'Windows Server*'" -Properties Name | select -ExpandProperty name))
{
$servers.add($server) | Out-Null
}
$servers.Sort()
$userAccount = Read-Host "Enter account to scan for"
Write-Host ""
foreach ($server in $servers)
{
Write-Host "$server"
$ErrorActionPreference = 'Stop'
try
{
$session = ((quser $userAccount /SERVER:$server)[1] -split "\s+")[3]
logoff /SERVER:$server $session
Write-Host " The user was logged into session #$session. They have been LOGGED OFF." -ForegroundColor Yellow
}
catch
{
if ($_.Exception.Message -match 'No user exists')
{
Write-Host " User is not logged in." -ForegroundColor Green
}
}
}

Powershell: Retrieving LogonDate in Active Directory

I've a list of computers, I'm checking if they are connected, if they aren't check with AD and "spit out" the one that aren't connecting for more than 3 months.
If it's connected then check if a services is installed.
Here's my code:
Import-Module ActiveDirectory
$datecutoff = (Get-Date).AddDays(-90)
Get-Content "C:\powershell\pc.txt" |
foreach {
if (-not (Test-Connection -comp $_ -quiet)){
Write-host "$_ is down" -ForegroundColor Red
$LastLog = Get-ADComputer -Identity $_ | Select LastLogonDate
if($LastLog -lt $datecutoff){
Write-host "$_ is offline for more than 3 months" -ForegroundColor Yellow
}
} Else {
$service = get-service -name masvc -ComputerName $_ -ErrorAction SilentlyContinue
if ($service ){
write-host "$_ Installed"
} else {
Write-host "$_ Not Installed"
}
}
}
When it finds a disconnected computer it gives me the following error:
Cannot compare "#{LastLogonDate=}" to "2020.04.16 18:49:19" because the objects are not the same type or the object "#{LastLogonDate=}" does not implement "IComparable".
At line:10 char:20
+ if($LastLog -lt $datecutoff){
+ ~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], ExtendedTypeSystemException
+ FullyQualifiedErrorId : PSObjectCompareTo
I know the error happens because my variable is saving wrong info, but I cannot find a way to only select the date in the AD.
Is there anyway to do this?
Thanks in advance.
You have a couple of issues. You'll need to request that LastLogonDate is returned with Get-ADComputer as its not by default. You'll need to use the dotted notation method of selecting property LastLogonDate from the $LastLog object so your compare works.
Import-Module ActiveDirectory
$datecutoff = (Get-Date).AddDays(-90)
Get-Content "C:\powershell\pc.txt" |
foreach {
if (-not (Test-Connection -comp $_ -Quiet)) {
Write-Host "$_ is down" -ForegroundColor Red
$LastLog = Get-ADComputer -Identity $_ -Properties LastLogonDate
if ($LastLog.LastLogonDate -lt $datecutoff) {
Write-Host "$_ is offline for more than 3 months" -ForegroundColor Yellow
}
} Else {
$service = Get-Service -Name masvc -ComputerName $_ -ErrorAction SilentlyContinue
if ($service ) {
Write-Host "$_ Installed"
} else {
Write-Host "$_ Not Installed"
}
}
}
Welcome to stackoverflow, please read https://stackoverflow.com/help/someone-answers
Side note. You can filter for aged computers like this Get-ADComputer -Filter 'LastLogonDate -lt $datecutoff'

Not able to convert from PScustomobject to Arraylist

I am trying to get all the list of patches from multiple servers. I am using invoke command with -asjob parameter to get the patch list from all servers. Running the below code.
I am getting the below error. I have tried with
Get-CIMInstance -Class Win32_QuickFixEngineering
and with
Get-WmiObject -Class Win32_QuickFixEngineering
but keep getting same error.
$Servers = Get-Content "C:\Users\Suman.Ghosh\Servers.txt"
[System.Collections.ArrayList]$All_Jobs = #()
[System.Collections.ArrayList]$Updated_Servers_List = #()
[System.Collections.ArrayList]$Jobs_Output = #()
$Patches_to_lookfor = #(
'KB4462926',
'KB4462941'
)
foreach ($S in $Servers) {
if (Test-Connection -ComputerName $S -Count 1 -Quiet) {
$Updated_Servers_List += $S
$All_Jobs += Invoke-Command -ComputerName $S -ScriptBlock {Get-HotFix} -AsJob
} else {
Write-Warning "Computer $S is not running"
}
}
Write-Host "below Jobs are running" -ForegroundColor Cyan
$All_Jobs
Write-Host "waiting for jobs to finish" -ForegroundColor Cyan
$All_Jobs | Wait-Job
$temp = #()
$flag = $false
foreach ($job in $All_Jobs) {
$Jobs_Output += Get-Job $job.Id | Receive-Job | Select HotFixID, CSNAME
}
foreach ($Job_output in $Jobs_Output) {
Write-Host $Job_output -ForegroundColor Green
### DO some stuff
}
Cannot convert value "#{HotFixID=KB4020449; CSName=mit1epxa2}" to type
"System.Collections.ArrayList".
Error: "Cannot convert the "#{HotFixID=KB4020449; CSName=mit1epxa2}" value
of type "Selected.System.Management.Automation.PSCustomObject" to type
"System.Collections.ArrayList"."
At line:1 char:10
+ foreach ($Job_output in $Jobs_Output) {
+ ~~~~~~~~~~~
+ CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
+ FullyQualifiedErrorId : RuntimeException
Ok, let's see if my second answer gets deleted (with no notification) by people who don't know the topic. I believe you have run a command like this on $job_output (no "s"):
[collections.arraylist]$job_output = #()
Then in the loop at the bottom, an exception is created because a pscustomobject can't be cast to a collections.arraylist with the $job_output variable. $jobs_output (with the "s") is an arraylist of [pscustomobjects]'s created by select.
foreach ($Job_output in $Jobs_Output) {
Write-Host $Job_output -ForegroundColor Green
### DO some stuff
}

Powershell script to remove groups from users

I found this script to remove groups from a single user but i'm afraid to try it in my environment:
Question - is there a test lab online where i can run these scripts without breaking my own environment? Also can someone with more scripting/powershell knowledge verify that this is safe to run if i want to remove groups from a user? I was instructed to run the script with an argument after it i.e. c:/sripts/removegroups.ps1 username#domain" is that correct?
$user = $args[0] if (!$args[0]) {
} $mailbox=get-mailbox $user
$dgs= Get-DistributionGroup
foreach($dg in $dgs){
$DGMs = Get-DistributionGroupMember -identity $dg.Identity
foreach ($dgm in $DGMs){
if ($dgm.name -eq $mailbox.name){
write-host 'User Found In Group' $dg.identity
Remove-DistributionGroupMember $dg.Name -Member $user
}
}
}
You could use the whatif switch on the Remove-DistributionGroupMember command
$user = $args[0] if (!$args[0]) {
} $mailbox=get-mailbox $user
$dgs= Get-DistributionGroup
foreach($dg in $dgs){
$DGMs = Get-DistributionGroupMember -identity $dg.Identity
foreach ($dgm in $DGMs){
if ($dgm.name -eq $mailbox.name){
write-host 'User Found In Group' $dg.identity
Remove-DistributionGroupMember $dg.Name -Member $user -Whatif
}
}
}
The WhatIf switch instructs the command to simulate the actions that it would take on the object. By using the WhatIf switch, you can view what changes would occur without having to apply any of those changes. You don't have to specify a value with the WhatIf switch.
http://technet.microsoft.com/en-us/library/aa998016(v=exchg.150).aspx
Set $WhatIfPreference to $true, and all the commands in the script should display what would have happened had they been run for real. This is (slightly) easier than modifying the script commands one by one.
Would it look something like this?
$WhatIfPreference = $true
$user = $args[0] if (!$args[0]) {
} $mailbox=get-mailbox $user
$dgs= Get-DistributionGroup
foreach($dg in $dgs){
$DGMs = Get-DistributionGroupMember -identity $dg.Identity
foreach ($dgm in $DGMs){
if ($dgm.name -eq $mailbox.name){
write-host 'User Found In Group' $dg.identity
Remove-DistributionGroupMember $dg.Name -Member $user
}
}
}
PS C:\Windows\system32> $WhatIfPreference = $true
PS C:\Windows\system32> $user = $args[0] if (!$args[0]) {
At line:1 char:18
+ $user = $args[0] if (!$args[0]) {
+ ~~
Unexpected token 'if' in expression or statement.
At line:1 char:33
+ $user = $args[0] if (!$args[0]) {
+ ~
Missing closing '}' in statement block.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordEx
ception
+ FullyQualifiedErrorId : UnexpectedToken
PS C:\Windows\system32>
PS C:\Windows\system32> } $mailbox=get-mailbox $user
At line:1 char:1
+ } $mailbox=get-mailbox $user
+ ~
Unexpected token '}' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordEx
ception
+ FullyQualifiedErrorId : UnexpectedToken
PS C:\Windows\system32>
PS C:\Windows\system32> $dgs= Get-DistributionGroup
WARNING: By default, only the first 1000 items are returned. Use the ResultSize
parameter to specify the number of items returned. To return all items,
specify "-ResultSize Unlimited". Be aware that, depending on the actual number
of items, returning all items can take a long time and consume a large amount
of memory. Also, we don't recommend storing the results in a variable. Instead,
pipe the results to another task or script to perform batch changes.
PS C:\Windows\system32>
PS C:\Windows\system32> foreach($dg in $dgs){
>>enter code here
>> $DGMs = Get-DistributionGroupMember -identity $dg.Identity
>> foreach ($dgm in $DGMs){
>> if ($dgm.name -eq $mailbox.name){
>>
>> write-host 'User Found In Group' $dg.identity
>> Remove-DistributionGroupMember $dg.Name -Member $user

Powershell - verify object exists in AD

i have a text file containing arround 100 servers, how can i push these into a script and test if they exist within AD? I have a simple script below:
$serverlist = get-content ServerList.txt
foreach ($server in $serverlist) {
if (Get-ADComputer $serverlist ) {
Write-Host "#########################"
Write-Host "Computer object exists"
Write-Host "#########################"
}
else {
Write-Host "#########################"
Write-Host "Computer object NOT FOUND"
Write-Host "#########################"
}
}
the above does not work returning a error:
Get-ADComputer : Cannot convert 'System.Object[]' to the type 'Microsoft.ActiveDirectory.Management.ADComputer' required by parameter 'Identity'. Specified method is not supported.
Can someone please explain does the get-adcomputer only allow a single object? Also if i remove the txt file and add a server shown below:
if (Get-ADComputer "server name" )
The above provides only results if the server exists within AD, if the server does not the error is shown below:
Get-ADComputer : Cannot find an object with identity: 'iuiub' under: 'DC=####,DC=#####,DC=#####'
Thank you for any insight / help!
Phil
Create an array - #(). If the array has 1 or more objects in it - which is $true - then you know the computer exists. If the array has 0 objects in it - which is $false- then you know the computer doesn't exist. I know some people don't like the ErrorAction to be set to SilentlyContinue but you're "Outputting an Error" if an error does occur.
$serverlist = get-content ServerList.txt
foreach ($server in $serverlist) {
if (#(Get-ADComputer $server -ErrorAction SilentlyContinue).Count) {
Write-Host "#########################"
Write-Host "Computer object exists"
Write-Host "#########################"
}
else {
Write-Host "#########################"
Write-Host "Computer object NOT FOUND"
Write-Host "#########################"
}
}
Another thing you could try are try catch blocks. Sorta like this:
$serverlist = get-content ServerList.txt
foreach ($server in $serverlist) {
try{
Get-ADComputer $server -ErrorAction Stop
Write-Host "#########################"
Write-Host "Computer object exists"
Write-Host "#########################"
}
catch{
Write-Host "#########################"
Write-Host "Computer object NOT FOUND"
Write-Host "#########################"
}
}
Line 3, change $serverlist to $server
With regards to handling a not found result. I'd try flipping the logic :
$serverlist = get-content ServerList.txt
foreach ($server in $serverlist) {
$tempVar = Get-ADComputer $server
if ($tempVar -like "Get-ADComputer : Cannot find an object with identity" ) {
Write-Host "#########################"
Write-Host "Computer object NOT FOUND"
Write-Host "#########################"
}
else{
Write-Host "#########################"
Write-Host "Computer object exists"
Write-Host "#########################"
}
}
In order to get a more helpful output, I'd go with the following... You'll just have a list of green and red lines indicating which server was found and which one wasn't.
$serverlist = get-content ServerList.txt
foreach ($server in $serverlist) {
try {
Get-ADComputer $server -ErrorAction Stop | Out-Null
Write-Host "$($server) exists" -ForegroundColor DarkGreen
}
catch {
Write-Host "$($server) NOT FOUND" -ForegroundColor DarkRed
}
}