PowerShell -Filters Failing on -notlike comparison - powershell-4.0

I have this script trying to pull inactive users from AD, but if someone doesn't have a Title, they don't get picked up. I tested the logic on an empty title for a single user, which returned as true, but when it runs through the foreach, it doesn't work (output shows only people with a Title are valid). I thought maybe the lastlogontimestamp comparison wasn't working so I added lastlogondate, but seems the Title is still the problem and I have no idea why?
#Inactivity Process
Import-Module ActiveDirectory
# Gets time stamps for all User in the domain that have NOT logged in since after specified date. Exludes Prism and PlanLink providers.
$DaysInactive = 365
$time = (Get-Date).Adddays(-($DaysInactive))
$Out_file = "C:\scripts\adcleanup\Inactivity-365days-or-longer_$((Get-Date).ToString('MM-dd-yyyy')).csv"
$Out_file2 = "C:\scripts\adcleanup\FailInactivity-365days-or-longer_$((Get-Date).ToString('MM-dd-yyyy')).csv"
# Get all AD User with lastLogonTimestamp less than our time and set to enabled. Check All Users for this...
$Users = Get-ADUser -Filter {samaccountname -like "s0*" -and (enabled -eq $true) -and (Title -notlike "*PRISM*") -and (Title -notlike "*PlanLink*") } -Properties samaccountname,name,enabled,Title,LastLogontimestamp, lastlogondate |
select SamAccountname,Name,Title,#{Name="LastLogonTimeStamp"; Expression={[DateTime]::FromFileTime($_.lastLogonTimestamp)}},lastlogondate, enabled
Foreach ($User in $Users) {
If (($user.LastLogontimestamp -le $time) -or ($user.LastLogondate -le $time)) {
$User| export-csv $Out_file -notypeinformation -append
}
Else {
$User | export-csv $Out_file2 -notypeinformation -append
}
}

I figured it out.
If (($user.LastLogontimestamp -le $time) -or ($user.LastLogondate -le $time) -or ($user.title -eq "") -and ($user.title -notlike "*PRISM*") -and ($User.title -notlike "*Planlink*") -and (!([string]::IsNullOrEmpty($user.lastlogondate)))) {

Related

Powershell script to deploy language during autopilot (based on choosed keyboard)

So Alex Semibratov made a script that, based on the choice of the second (additional) keyboard, changes the language of the system to the one matching the keyboard language choice and sets everything as default. (Full localization of Windows 10/11 from Autopilot)
I came up with the idea that you can use the selection of the first keyboard (skipping the additional keyboard selection) which seems more obvious to the user. I found an entry in the registry where there is information about the keyboard language used:
$rpath = 'registry::HKEY_USERS\.DEFAULT\Keyboard Layout\substitutes'
$KB_lng_code = Get-Item -Path $rpath |select -ExpandProperty property | %{Get-ItemProperty $rpath | select -ExpandProperty $_}
$KB_lng_code
Switch ($KB_lng_code)
{
"0000040a" {Write-Host "es-es"}
"00000411" {Write-Host "ja-jp"}
"00000804" {Write-Host "zh-CN"}
"00000404" {Write-Host "zh-TW"}
}
I edited the first part of Alex script:
Start-Transcript -Path "$env:PROGRAMDATA\Localization.log" | Out-Null
$regpath = 'registry::HKEY_USERS\.DEFAULT\Keyboard Layout\substitutes'
$Languages = Get-Item -Path $regpath |select -ExpandProperty property | %{Get-ItemProperty $regpath | select -ExpandProperty $_}
if ($languages -eq "00000415") {$languages = 'pl-pl'}
elseif($languages -eq "0000040c") {$languages = 'fr-fr'}
elseif($languages -eq "00000816") {$languages = 'pt-pt'}
elseif($languages -eq "0000040a") {$languages = 'es-es'}
$Language = $languages
$inputLanguageID = $null
if ($language -eq $null)
{
$IPInfo = Invoke-RestMethod http://ipinfo.io/json
$Language = $IPInfo.country
}
$GeoID = (Get-ItemProperty -Path 'registry::HKEY_USERS\.DEFAULT\Control Panel\International\Geo').Nation
$LanguageExperiencePacklanguage = $Language
and the part with languages filled with the proper values: (example)
{$_ -eq "00000415" -or $_ -eq "pl-pl"} {
$applicationId = "9nc5hw94r0ld"
$GeoID = 191
$LanguageExperiencePacklanguage = "pl-PL"
if($inputLanguageID -eq $null) {$inputLanguageID = "0415:00000415"}
}
It finds the current keyboard language and installs the proper system language BUT I think it is kind of messy. Any ideas on how to make it better?
Regards

Powershell: Find installed Antivirus & state, filtering out Windows Defender

I came across the basis of this script in another post here, however, I would like to take it a bit further and have been experimenting. What I am seeking to achieve is to get the name, state of the antivirus installed on the device and of course I want to filter out Windows Defender. Here is what I have so far...
The issue I have with the current code that I am not sure how to get around is that I am getting the state code for Windows Defender also.
I would greatly appreciate your advise and assistance.
clear
function Get-AntivirusName {
[cmdletBinding()]
param (
[string]$ComputerName = "$env:computername" ,
$Credential
)
$wmiQuery = "SELECT * FROM AntiVirusProduct"
$AntivirusProduct = Get-WmiObject -Namespace "root\SecurityCenter2" -Query $wmiQuery #psboundparameters
[array]$AntivirusNames = $AntivirusProduct.displayName | sort -unique
[array]$AntivirusState = $AntivirusProduct.productState | sort -unique
$AntivirusState
Switch($AntivirusNames) {
{$AntivirusNames.Count -eq 0}{"Anti-Virus is NOT installed!";Continue}
{$AntivirusNames.Count -eq 1 -and $_ -eq "Windows Defender"} {Write-host "ONLY Windows Defender is installed!";Continue}
{$_ -ne "Windows Defender"} {"Antivirus Product(s): $_."}
}
}
Get-AntivirusName
If you want to rule out Windows Defender, but do want to get a console message, I would change the function like below:
function Get-AntivirusName {
[cmdletBinding()]
param (
[string]$ComputerName = $env:COMPUTERNAME,
$Credential
)
$wmiQuery = "SELECT * FROM AntiVirusProduct"
$AntivirusProduct = #(Get-CimInstance -Namespace "root\SecurityCenter2" -Query $wmiQuery #psboundparameters)
if ($AntivirusProduct.Count -eq 0) {
Write-Host 'Anti-Virus is NOT installed!' -ForegroundColor Red
}
elseif ($AntivirusProduct.Count -eq 1 -and $AntivirusProduct.displayName -like '*Windows Defender*') {
Write-Host 'ONLY Windows Defender is installed!' -ForegroundColor Cyan
}
else {
# filter out Windows Defender from the list
$AntivirusProduct = $AntivirusProduct | Where-Object {$_.displayName -notlike '*Windows Defender*'} | Sort-Object -Unique
# output objects with both the product name and the status
foreach ($avProduct in $AntivirusProduct) {
[PsCustomObject]#{
AV_Product = $avProduct.displayName
AV_Status = $avProduct.productState
}
}
}
}
Get-AntivirusName

PowerShell 2 - Displaying Share Directory Where Everyone has Full Control

PowerShell Version: 2 (I understand the risks)
The following command outputs all shares where the "everyone" user group has access:
$Found = #()
Get-WmiObject win32_logicalsharesecuritysetting |
ForEach-Object {$Path = "\\localhost\\" + $_.Name; Get-Acl -Path $Path |
Select-Object Path -ExpandProperty Access |
ForEach-Object {If($_.IdentityReference -eq 'Everyone'){$Found += $_.Path}}}
Write-Host "Found: $($Found.Count)"
Write-Host "Share locations:"
$Found | ForEach-Object {Write-Host $_.Replace('Microsoft.PowerShell.Core\FileSystem::\\localhost\','')}
Can the command above be enhanced to only display shares where the "everyone" user group has "full control" only?
If the radio button is not selected, don't display anything in the output, however, if that full control radio button is selected for the user group "everyone", display an output:
so in my program i use this piece of code:
$Shares = Get-WmiObject -Class Win32_LogicalShareSecuritySetting
foreach($Share in $Shares) {
foreach($perm in $Permissions.Descriptor.DACL) {
if($Perm.Trustee.Name -eq "EveryOne" -and $Perm.AccessMask -eq "2032127" -and $Perm.AceType -eq 0) {
#EveryOneFullControl is true so do something
} else {
#EveryOneFullControl is false so do something
}
}
}

How to assign multiple 'where' conditions to variable in Powershell

I am working on a Powershell script (with a GUI) to help my colleagues easier find redundant and disabled AD accounts.
Here is a little preview...
$props = "Name, Enabled, PasswordExpired, Company,passwordNeverExpires, Office"
$propsAsArray = $props -split ',\s*'
Get-ADUser -filter * -properties $propsAsArray | where {$_.Enabled -eq $true} | where {$_.PasswordNeverExpires -eq $false}| where {$_.passwordexpired -eq $false} | Select-Object $propsAsArray | Export-csv -Path "C:\report.csv"
This all works fine and outputs a CSV report.
The snag though is how to assign all the possible combinations and permutations of AD account status to a variable and later substitute in the variable into the Get-ADUser cmdlet (depending on which radio button the user clicks in the GUI).
I've tried all can think of but only ever get back the error Expressions are only allowed as the first element of a pipeline.
I'm sure that $accountStatus = "where {$_.Enabled -eq $true} | where {$_.PasswordNeverExpires -eq $false}" (or subtle variants) are not how it is done.
I'm relatively new to Powershell and am eager to get experience. Thanks, William.
Note: This answer addresses the question as asked, using a generalized Where-Object-based solution based on script blocks ({ ... }), but in the case at hand a string-based solution based on Get-ADUser's -Filter parameter, which efficiently filters at the source, as shown in the second command in Thomas' answer, is preferable.
Store an array of script blocks ({ ... }) representing the conditionals in a variable, and use an array of indices to select which conditionals to apply situationally, based on the user's GUI selections:
# All individual conditions to test, expressed as an array of script blocks.
# Note: No need for `-eq $true` to test Boolean properties, and
# `-eq $false` is better expressed via the `-not` operator.
$blocks =
{ $_.Enabled },
{ -not $_.PasswordNeverExpires },
{ $_.PasswordExpired }
# Select the subset of conditions to apply using AND logic, using
# an array of indices, based on the GUI selections.
$indices = 0..2 # e.g., all 3 conditions (same as: 0, 1, 2)
Get-ADUser -Filter * -properties $propsAsArray | Where-Object {
# The following is equivalent to combining the conditionals of interest
# with -and (AND logic):
foreach ($block in $blocks[$indices]) { # Loop over selected conditionals
if (-not (& $block)) { return $false } # Test, and return $false instantly if it fails.
}
$true # Getting here means that all conditions were met.
}
Note how each block is executed via &, the call operator.
You can condense your multiple Where-Object calls by concatenating each condition with and:
Get-ADUser -Filter * -Properties $propsAsArray | Where-Object {(($_.Enabled -eq $true) -and ($_.PasswordNeverExpires -eq $false)) -and ($_.passwordexpired -eq $false)} | Select-Object $propsAsArray | Export-csv -Path "C:\report.csv"
But as Olaf already pointed out in the comments, it is even better to already use the -Filter parameter of Get-ADUser. There, you can use a similar combination of your conditions:
Get-ADUser -Filter {((Enabled -eq $true) -and (PasswordNeverExpires -eq $true)) -and (passwordexpired -eq $false)} -Properties $propsAsArray | Select-Object $propsAsArray | Export-csv -Path "C:\report.csv"

Account expiry dates or account Never expire for all AD users

While I am running the below command getting expiration_date is blank.
Is it possible to get the 'Never expire' instead of blank in expiration_date?
Import-Module ActiveDirectory
$Groups = Get-ADGroup -filter {Name -like "SSL_VPN_Users" } | Select-Object Name
ForEach ($Group in $Groups) {
Get-ADGroupMember -identity $($group.name) -recursive |
Get-ADUser -Properties samaccountname,mail,AccountExpires |
select samaccountname,mail,#{l="expiration_date";e={[datetime]::fromfiletime($_.accountexpires)}} |
Export-csv -path C:\SSLVPN\SSL_VPN_Users.csv -NoTypeInformation
}
The problem is probably when the account never expires the value of AccountExpires is the max. int64 value which results in an ArgumentOutOfRangeException when calling [datetime]::FromFileTime for it.
Therefore try the following - I introduced the helper function accountExpiresToString for better readability of the expression script block but you can pack the function's code directly within the script block if you prefer that.
function accountExpiresToString($accountExpires) {
if (($_.AccountExpires -eq 0) -or
($_.AccountExpires -eq [int64]::MaxValue)) {
"Never expires"
}
else {
[datetime]::fromfiletime($accountExpires)
}
}
Import-Module ActiveDirectory
...
ForEach ($Group in $Groups) {
Get-ADGroupMember ... |
Get-ADUser -Properties ...,AccountExpires |
Select-Object #{l="expiration_date";e={ accountExpiresToString($_.AccountExpires)}} |
Export-Csv ...
}
Update: If of interest, here is a page on MSDN describing that 0 and 0x7FFFFFFFFFFFFFFF ([int64]::MaxValue) indicates an account that never expires.

Resources