How do I create an exclusion into query results? - powershell

Forgive me for I am relatively new to PowerShell. I have an issue were we need to log off all disconnected users with the exception of one ID. I found this script which does a great job logging off the disconnected users. My question is how would I modify this section to ignore one or more specified users from the query results?
function Get-Sessions
{
$queryResults = query session
$starters = New-Object psobject -Property #{"SessionName" = 0; "UserName" = 0; "ID" = 0; "State" = 0; "Type" = 0; "Device" = 0;}
foreach ($result in $queryResults)
{
try
{
if($result.trim().substring(0, $result.trim().indexof(" ")) -eq "SESSIONNAME")
{
$starters.UserName = $result.indexof("USERNAME");
$starters.ID = $result.indexof("ID");
$starters.State = $result.indexof("STATE");
$starters.Type = $result.indexof("TYPE");
$starters.Device = $result.indexof("DEVICE");
continue;
}
New-Object psobject -Property #{
"SessionName" = $result.trim().substring(0, $result.trim().indexof(" ")).trim(">");
"Username" = $result.Substring($starters.Username, $result.IndexOf(" ", $starters.Username) - $starters.Username);
"ID" = $result.Substring($result.IndexOf(" ", $starters.Username), $starters.ID - $result.IndexOf(" ", $starters.Username) + 2).trim();
"State" = $result.Substring($starters.State, $result.IndexOf(" ", $starters.State)-$starters.State).trim();
"Type" = $result.Substring($starters.Type, $starters.Device - $starters.Type).trim();
"Device" = $result.Substring($starters.Device).trim()
}
}
catch
{
$e = $_;
Write-Log "ERROR: " + $e.PSMessageDetails
}
}
}
Thank you for any input you may have.

So you want to omit certain results? You are using PowerShell objects so this should be easy with Where-Object
$omissions = "user1","user2"
foreach ($result in $queryResults)
{
# Stuff inside the loop
} | Where-Object{$omissions -notcontains $_.Username}
Tack on the where-object and we use -notcontains to see if a given user is not in the array of $omissions. Which is of course a list of users.
Caveat
You might have issues with the output of that foreach construct. I have seen this in PowerShell versions earlier than 3.0. If that does happen you could just capture the New-Objects into an array to later filter or use ForEach-Object.

Related

How to iterate through an array of objects in Powershell

I'm doing some basic validation on form fields. What's the correct way to iterate through an array of objects to validate them? When I try the below I get
The property 'BackColor' cannot be found on this object. Verify that the property exists and can be set.
I guess what I'm missing is a way of telling Powershell these are references to other variables, rather than variables themselves.
$MandatoryFields = #(
'txtUsername',
'txtFirst',
'txtLast',
'txtEmail',
'ComboLicense'
)
ForEach ($Field in $MandatoryFields) {
If ([string]::IsNullOrWhitespace($Field.text)) {
$Validation = "failed"
$Field.BackColor = "red"
}
}
EDIT: Okay, what I needed was the actual variables in the array, like so:
$MandatoryFields = #(
$txtUsername,
$txtFirst,
$txtLast,
$txtEmail,
$ComboLicense
)
Try adding your objects to an array like below
$objects = [System.Collections.ArrayList]#()
$myObject = [PSCustomObject]#{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
$objects.add($myObject)
$myObject1= [PSCustomObject]#{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
$objects.add($myObject1)
foreach($obj in $objects){
$obj.firstname
}
I'm assuming your using System.Windows.Forms to create your form. If that's the case when adding controls you should assign a name to the control. Then you can loop through your controls and check if the control name matches your list of mandatory controls and then execute your check.
$MandatoryFields = #(
'txtUsername',
'txtFirst',
'txtLast',
'txtEmail',
'ComboLicense'
)
$Controls = MyForm.controls
ForEach ($c in $Controls) {
ForEach ($Field in $MandatoryFields) {
if ($c.Name -eq $Field) {
If ([string]::IsNullOrWhitespace($c.text)) {
$Validation = "failed"
$c.BackColor = "red"
}
}
}
}

Powershell Wrong output

guys i need help here, i want to return the $Location002 and $Location003 content look what is in output
$Location = "westus2"
$Location002 = "westeurope"
$Location003 = "eastasia"
[int]$VMCount = Read-Host "How many VMs?"
1..$VMCount | ForEach-Object {
$i = $_
# define name for VM, will be used for other resources
if ($i -eq 1) {
$locname = "$Location"
Write-Output $locname
}
else {
$locname = $("Location00" + "$i")
Write-Output $locname
}
}
output :
PS C:\Users\Marouane\Desktop\testpowershell> c:\Users\Marouane\Desktop\testpowershell\test.ps1
How many VMs?: 3
westus2
Location002
Location003
PS C:\Users\Marouane\Desktop\testpowershell>
i need to output westeurope and eastasia
Using a separate variable for each value in a group or list of things is a bit of an anti-pattern, you'll want to put them all in an array together instead:
# Define array of possible locations
# `$Locations[0]` will resolve to `westus2`
# `$Locations[1]` will resolve to `westeurope`, etc.
$Locations = #(
"westus2"
"westeurope"
"eastasia"
)
[int]$VMCount = Read-Host "How many VMs?"
1..$VMCount | ForEach-Object {
# Define the VM name
$name = "VirtualMachine$_"
# Pick next location from the $Locations array
# the % ensures we "wrap around" when we reach the end
$location = $Locations[($_ - 1) % $Locations.Length]
# Output a new object with Name + Chosen Location
[pscustomobject]#{
VMName = $name
Location = $location
}
}
Output for 3 VMs:
How many VMs?: 3
VMName Location
------ --------
VirtualMachine1 westus2
VirtualMachine2 westeurope
VirtualMachine3 eastasia
This is not how I would do it, but the more immediate problem is you're assigning a concatenated string to $location and writing to the output stream. I think what you want to do is reference the value of the earlier variable.
There are some clever syntaxes for that. I struggle to remember them. However below would be a start.
$Location = "westus2"
$Location002 = "westeurope"
$Location003 = "eastasia"
[int]$VMCount = Read-Host "How many VMs?"
1..$VMCount | ForEach-Object {
$i = $_
# define name for VM, will be used for other resources
if ($i -eq 1) {
$name = "$VMName"
$locname = "$Location"
Write-Output $locname
}
else {
$name = "$VMName" + "00" + "$i"
$locname = (Get-Variable ("Location00" + "$i")).Value
Write-Output $locname
}
}
Update With Alternative:
I'm still not sure what the goal is, but based on the original sample it would seem there's a 1 to 1 relationship between the location# and the VM number. That said if you go past the number of VMs you would have to adjust this to pick according to the intended pattern...
$Locations = 'westus2', 'westeurope', 'eastasia'
[int]$VMCount = Read-Host 'How many VMs?'
For( $i = 0; $i -lt $VMCount ; ++$i )
{
$Locations[$i]
}
Further Update:
Respective to Mathias's good answer :
$Locations = 'westus2', 'westeurope', 'eastasia'
[int]$VMCount = Read-Host 'How many VMs?'
For( $i = 0; $i -lt $VMCount ; ++$i )
{
$Locations[ $i % $Locations.Count ]
}
Using the modulus operator in this pattern is very efficient for distributing one list over another. I wrote a small post about My Modulus Obsession with this and some other uses.
You'll need to retrieve the variable's content with Get-Variable. You can also avoid the extra step of making an $i variable and instead use the automatic variable $_
$Location = "westus2"
$Location002 = "westeurope"
$Location003 = "eastasia"
[int]$VMCount = Read-Host "How many VMs?"
1..$VMCount | ForEach-Object {
# define name for VM, will be used for other resources
if ($_ -eq 1) {
$name = "$VMName"
$locname = "$Location"
Write-Output $locname
}
else {
$name = "$VMName" + "00" + "$_"
$locname = "Location00" + "$_"
Write-Output (get-variable $locname).value
}
}

PowerShell nested property iteration

Looking for some input on the scripts below. Essentially I'm retrieving some json data with Invoke-WebRequest. I needed to export many of the properties to CSV. The data returned from Invoke-WebRequest is contained in an array: $devicedetails. This script works for outputting to CSV.
& {
Foreach ($PC in $DeviceDetails)
{
Foreach ($AppName in $PC.categories)
{
ForEach ($App in $AppName.apps)
{
ForEach($Status in $App.health_status)
{
[pscustomobject] #{
"Device ID" = $PC.device_id
"Device Type" = $PC.device_type
"Device Name" = $PC.device_name
Nickname = $PC.nick_name
Last_Seen = $PC.last_seen
Compliance_Category_Status = $Appname.issue
Compliance_Category = $Appname.category_id
Product_Name = $App.name
Product_Vendor = $App.vendor
Product_Version = $App.version
Product_Health_Item = $Status.status
Product_Health_Status = $Status.issue
}
}
}
}
}
} | Export-CSV -PAth $Outfile -NoTypeInformation
Curious if this is the best way to output properties to CSV. Additionally, I now have the need to do some additional processes on the custom object I'm creating but if I assign a variable to that custom object as shown below, it takes several minutes to complete whereas just exporting to CSV takes 12-13 seconds. Why is the performance so bad?
$DeviceOutput= #()
Foreach ($PC in $DeviceDetails)
{
Foreach ($AppName in $PC.categories)
{
ForEach ($App in $AppName.apps)
{
ForEach($Status in $App.health_status)
{
$DeviceOutput += [pscustomobject] #{
"Device ID" = $PC.device_id
"Device Type" = $PC.device_type
"Device Name" = $PC.device_name
"Nickname" = $PC.nick_name
Compliance_Category_Status = $Appname.issue
Compliance_Category = $Appname.category_id
Product_Name = $App.name
Product_Vendor = $App.vendor
Product_Version = $App.version
Product_Health_Item = $Status.status
Product_Health_Status = $Status.issue
}
}
}
}
}

Adding an Exception into try catch

I have a question regarding the Script below the script checks multiple Mailservers against RBL Lists, the Problem is that some of the Lists (like hostkarma.junkemailfilter.com) have certain answers that do not mean that the IP is actually blacklisted.
So I want to add an Exception into the try..catch function that if hostkarma.junkemailfilter.com answers with 127.0.2.1 the Mailserver is not getting into $blacklistedOn.
The Script:
Param([string]$IP)
$statusAlive = "ScriptRes:Host is alive:"
$statusDead = "ScriptRes:No answer:"
$statusUnknown = "ScriptRes:Unknown:"
$statusNotResolved = "ScriptRes:Unknown host:"
$statusOk = "ScriptRes:Ok:"
$statusBad = "ScriptRes:Bad:"
$statusBadContents = "ScriptRes:Bad contents:"
$reversedIP = ($IP -split '\.')[3..0] -join '.'
$blacklistServers = #(
"dnsbl-3.uceprotect.net";
"dnsbl-2.uceprotect.net";
"dnsbl-1.uceprotect.net";
"ix.dnsbl.manitu.net";
"bl.spamcop.net";
"bl.spamcannibal.org";
"b.barracudacentral.org";
"ips.backscatterer.org";
"dnsbl.sorbs.net";
"cbl.abuseat.org";
"all.spamrats.com";
"black.uribl.com";
"multi.surbl.org";
"multi.uribl.com";
"truncate.gbudb.net";
"bl.blocklist.de";
"dnsbl.inps.de";
"bl.mailspike.net";
"bl.spameatingmonkey.net";
"db.wpbl.info";
"dnsbl.justspam.org";
"hostkarma.junkemailfilter.com";
"mail-abuse.blacklist.jippg.org";
"psbl.surriel.com";
"spam.dnsbl.anonmails.de";
"ubl.unsubscore.com";
"cblless.anti-spam.org.cn";
"cblplus.anti-spam.org.cn";
"spam.pedantic.org";
"dev.null.dk";
"blackholes.five-ten-sg.com";
"spamsources.fabel.dk";
"zen.spamhaus.org";
"spamguard.leadmon.net";
"dialups.visi.com";
"dnsbl.kempt.net";
"dnsbl.dronebl.org";
"no-more-funn.moensted.dk";
"relays.bl.kundenserver.de";
)
$blacklistedOn = #()
foreach ($server in $blacklistServers) {
$IPServer = "$reversedIP.$server"
try {
$null = [System.Net.Dns]::GetHostEntry($IPServer)
$blacklistedOn += $server
} catch { }
}
if ($blacklistedOn.Count -gt 0) {
# The IP was blacklisted on one or more servers; send your email here.
# $blacklistedOn is an array of the servers that returned positive results.
Write-Host "$statusAlive"$blacklistedOn
} else {
Write-Host "$statusDead"$blacklistedOn
}
Currently your script discards whatever is returned by your host lookup. To skip over an address if a particular response is returned you need to assign it to a variable and check that before actually adding the server to $blacklistedOn:
try {
$addr = [Net.Dns]::GetHostEntry($IPServer)
if (-not ($server -eq 'hostkarma.junkemailfilter.com' -and $addr.AddressList.IPAddressToString -contains '127.0.2.1')) {
$blacklistedOn += $server
}
} catch { }

Powershell [Ref] Value not updating main object

I'm running Powershell V2 on XP:
This is part of a larger script and I'm noticing some anomolies with the way I'm able to use reference objects to update the "master" object. This started off as a way to avoid typing out the complicated name of the property each time - I could easily expand out to the full name but now the reason for this behaviour is seriously bugging me.
[CmdletBinding()]
Param()
Function Breakhere {Write-Verbose " "}
Set-PSBreakpoint -Command Breakhere
$Data = #"
UserID
MyUser1
MyUser2
User3
"#
$Data = $Data|ConvertFrom-Csv
$Domains = "DomainA","DomainB"
$Props = "ParentContainer","AccountIsDisabled","employeeNumber"
$Connection = New-Object HashTable
ForEach ($Domain in $Domains)
{
Write-Verbose "Current Domain: $Domain"
# Add necessary headers to main data
$text1 = "$($Domain)_ADObject"
$text2 = "$($Domain)_Confidence"
$Data = $Data |Select *,$text1
$Data = $Data |Select *,$text2
#Bind to each domain and save the connection contexts into a hashtable
Write-Verbose "Binding to $Domain"
$Connection.Add($Domain,(Connect-QADService -service $Domain))
}
ForEach ($User in $Data)
{
ForEach ($Domain in $Domains)
{
$User."$($Domain)_ADObject" = Get-QADUser -Connection $Connection[$Domain] -SamAccountName $User.UserID -DontUseDefaultIncludedProperties -IncludedProperties $Props|Select $Props
# Referencing the confidence parameter does not seem to work.
$CF = [ref]$User."$($Domain)_Confidence"
# Weirdly, this one does work.
$AD = [ref]$User."$($Domain)_ADObject"
If ($AD.Value)
{
$CF.Value = 1
Breakhere # Break here and allow for opportunity to inspect $user and $CF objects
If ($AD.Value.AccountIsDisabled)
{
Write-Verbose "$Domain\$($User.UserID): Account Disabled"
$CF.Value *= 0.8
}
}
Else
{
Write-Verbose "$Domain\$($User.UserID): No AD Object found"
$CF.Value = 0
}
}
} #End ForEach $UserID
At the breakpoint, if I query $User, I receive something similar to the following:
UserID : MyUser1
DomainA_ADObject : #{ParentContainer=DomainA/Users; AccountIsDisabled=False; employeeNumber=123456}
DomainA_Confidence :
DomainB_ADObject :
DomainB_Confidence :
All good. Should I wish, I can even use the $AD ref object and update DomainA_ADobject:
$AD.Value.employeeNumber = 9999
$User
UserID : MyUser1
DomainA_ADObject : #{ParentContainer=DomainA/Users; AccountIsDisabled=False; employeeNumber=9999}
DomainA_Confidence :
DomainB_ADObject :
DomainB_Confidence :
However, try this with the $CF ref and the same thing doesn't happen
$CF.Value = 2
$CF
Value
-----
2
$User
UserID : MyUser1
DomainA_ADObject : #{ParentContainer=DomainA/Users; AccountIsDisabled=False; employeeNumber=9999}
DomainA_Confidence : *<====== Expecting this to update!*
DomainB_ADObject :
DomainB_Confidence :
Why the difference? Is there any way to query a [ref] object and see what it's pointing to? I can't see why one of these is working and the other isn't. They both seem to be set up in the same way. Tried this in ISE and console, same behaviour in both.
My guess is, that this is caused by dots in the name of domains.
Reducing this to basics $CF.Value = 1 does someting like
$Data[0].domain.name.net.au_Confidence.value = 1
This will not work. This will:
$Data[0]."domain.name.net.au_Confidence".value = 1
Perhaps this will fix it?:
$CF = [ref]$User."`"$($Domain)_Confidence`""