Proper way to create pscustomobject to add to array - arrays

What is the proper way to create / clear / initialize a object inside a for loop using the following method/syntax? There is a performance increases using this method.
$objComputer = [pscustomobject] #{}
I noticed if one of the systems does not exist in AD and returns an error or null the information from the previous entry/object is used in the array. For example Computer-03 is valid but BLAH (which is not) pulls from the previous entry of Computer-03.
function Get-ADComputers ($NameList) {
$arrayComputer = #();
foreach ($line in $NameList.Split("`r`n") | ? { $_ }) {
$PCName = $line.Trim()
$Computer = (Get-ADComputer -Identity $PCName -Properties *)
$objComputer = [pscustomobject] #{
Computer = $PCName
Active = $Computer.Enabled
Date = $Computer.PasswordLastSet
DaysOld = (Get-DaysOld $Computer.PasswordLastSet)
OU = $Computer.DistinguishedName
}
write-host $objComputer
$arrayComputer += $objComputer
$objComputer = $null;
} return $arrayComputer
}
RESULTS
Computer Active Date DaysOld
Computer-01 TRUE 4/12/2015 8:16 -29
Computer-02 TRUE 5/4/2015 7:11 -7
Computer-03 TRUE 4/20/2015 9:01 -21
BLAH TRUE 4/20/2015 9:01 -21
Computer-03 TRUE 4/6/2015 8:14 -35
Computer-04 TRUE 5/9/2015 17:17 -1
Computer-05 TRUE 4/17/2015 12:04 -24
Thank you for your help! :)
EDIT EXAMPLE WITH TRY CATCH:
function Get-ADComputers ($NameList) {
$arrayComputer = #();
foreach ($line in $NameList.Split("`r`n") | ? { $_ }) {
$Computer = $null
$PCName = $line.Trim()
try {
$Computer = (Get-ADComputer -Identity $PCName -Properties *)
$objComputer = [pscustomobject] #{
Computer = $PCName
Active = $Computer.Enabled
Date = $Computer.PasswordLastSet
DaysOld = (Get-DaysOld $Computer.PasswordLastSet)
OU = $Computer.DistinguishedName
}
} catch {
$objComputer = [pscustomobject] #{
Computer = "$PCName"
Active = "Missing"
Date = "N/A"
DaysOld = "N/A"
OU = "N/A"
}
}
write-host $objComputer
$arrayComputer += $objComputer
$objComputer = $null;
} return $arrayComputer
}

If the call to Get-ADComputer fails, $Computer is not cleared out. You'll need to handle the error in one way or another. A simple solution:
$Computer = $null
$Computer = (Get-ADComputer -Identity $PCName -Properties *)
if(!$Computer) { #handle a missing computer
$objComputer = [pscustomobject] #{
Computer = "Computer not found"
Active = "FALSE"
Date = "N/A"
DaysOld = "N/A"
OU = "N/A"
}
}
You can also use a try/catch block. If you don't care all that much, you can use -ErrorAction SilentlyContinue.

Related

Multiple varibales from a function into an array in Powershell

I have a function that returns several things and I need to store them into an array seperately.
The code I currently have is like so:
Function ADlocation{
Try{
$ADDetails = Get-ADComputer - Identity $Servername -Properties Description,LastLogOnTimeStamp -ErrorAction SilentlyContinue -ErrorVariable ADFail
}
Catch [Exception]{
return "$($Servername) not in AD"
}
If(!ADFail){
return (Get-ADOrganizationalUnit -Identity $(ADDetails.DistinguishedName.Replace("CN=$($ADDetails.Name),","")) -Properties canonicalName).canonicalName
return $ADDetails.Description
return ([datetime]::FromFileTime($ADDetails.LastLogonTimeStamp)).ToString()
}
}
$Output = #()
foreach ($ipAddress in $iplist){
$Servername = [System.Net.Dns]::GetHostByAddress($ipAddress).Hostname
if(Test-Connection $ipAddress -Quiet){
$Output += [PSCustomObject]#{
ip = $ipAddress
Name = $ServerName
Pingable = "Yes"
ADLocation = ADlocation
AdDescription = ADlocation
LAstLogOnTime = ADlocation
}
} else {
$Output +=[PSCustomObject]#{
ip = $ipAddress
Name = "N/A"
Pingable = "No"
}
}
}
$Output | Export-Csv -path $OutputPath -NoTypeInformation
I am unsure what i should call to specifically get the "ADlocation", "ADDescription" and LastLogOnTime
There are a couple of things amiss in your code. As commented, the three return statements in the function. In fact, you don't really need a helper function for this..
Also, there is a syntax error on - Identity $Servername, where the space should not be there between the hyphen and the parameter name Identity.
Then, if you want to output a valid CSV, you need to specify the same objects with the same properties, both when succeeded and when failed.
I think the easiest way to do this, is to merge success/failed like below:
Assuming your $iplist variable is an array of IP addresses
$OutputPath = 'D:\Test\computers.csv' # enter the path and filename you want here
# loop over the IP addresses in the list
$Output = foreach ($ipAddress in $iplist) {
# initialize some variables
$pingable = 'No'
$Servername, $ADDetails = $null
if (Test-Connection -ComputerName $ipAddress -Quiet -Count 1) {
$pingable = 'Yes'
# GetHostByAddress is obsolete, use GetHostEntry
$Servername = [System.Net.Dns]::GetHostEntry($ipAddress).Hostname
# rather use Filter than Identity so exceptions can be silenced with -ErrorAction SilentlyContinue
$ADDetails = Get-ADComputer -Filter "Name -eq '$Servername'" -Properties Description,LastLogOnDate, CanonicalName -ErrorAction SilentlyContinue
}
# simply output an object to be collected in variable $Output
[PSCustomObject]#{
IP = $ipAddress
Name = if ([string]::IsNullOrWhiteSpace($ServerName)) { 'N/A' } else { $ServerName }
Pingable = $pingable
ADLocation = if ($ADDetails) { Split-Path -Path $ADDetails.CanonicalName -Parent } else { 'N/A' }
ADDescription = if ($ADDetails) { $ADDetails.Description } else { 'N/A' }
LastLogOnDate = if ($ADDetails) { $ADDetails.LastLogOnDate } else { 'N/A' }
}
}
# output on screen
$Output | Format-Table -AutoSize
# output to CSV file
$Output | Export-Csv -Path $OutputPath -NoTypeInformation

Array returned has an unexpected element in Powershell

An array returned from a function has an unexpected element appended to it, and I cannot understand how to fix it. A help will be so much appreciated.
The array in function A, for some unknown reason is different to the array in function B that calls the function A.
function functionA(...)
{
[...]
$status = (,#("reserved",$proj,$id));
Write-Host "Status in FunctionA to FunctionB: "$status
[...]
return $status
}
I get from the Write-Host above: Status in FunctionA to FunctionB: reserved B hfuhfkhec8u8b7hf4smeu43gn4
function functionB(...)
{
[...]
$funcA = functionA
Write-Host "Status in FunctionB from FunctionA: "$funcA
[...]
}
I get from the Write-Host above: Status in FunctionB from FunctionA: 1 reserved B hfuhfkhec8u8b7hf4smeu43gn4. You can observe the $status in functionA has not the value 1, so why I get the value 1 appended in the array? What may I do to fix it?
Please check the complete code bellow, where FunctionA is CheckReservation and FunctionB is PeriodicCheckIn
PS: I noted that if I comment the function InformationMsgBox to do not call if in CheckReservation, then the code works.
function CheckReservation($headers){
$events = GetCalendarEvents($headers)
$users = Get-IniFile ..\ini\Users.ini
$user = $users.$env:UserName.email
$error = "There is not any confirmed reservation for this machine."; $status = (,#("NoReservations",$error));
$calendarId = Get-IniFile ..\ini\Computers.ini
$calendarId = $calendarId.$env:Computername.calendarId
foreach($item in $events.items)
{
if($item.status -match "confirmed")
{
$attender = $item.attendees.email |
Where-Object {$_ -contains $user}
$calendar = $item.attendees |
Where-Object {$_.email -contains $calendarId}
$calendarEmail = $calendar.email
$calendarStatus = $calendar.responseStatus
$organizer = $item.organizer.email | Where-Object {$_ -contains $user}
if(($attender -match $user) -or ($item.organizer.email -match $user))
{
if(($calendarStatus -match "accepted") -or ($item.organizer.email -match $calendarId))
{
$current = [Xml.XmlConvert]::ToString((get-date),[Xml.XmlDateTimeSerializationMode]::Local)
if(((get-date $current) -ge (get-date $item.start.dateTime)) -and ((get-date
$current) -lt (get-date $item.end.dateTime)))
{
$timespan = NEW-TIMESPAN –Start (get-date $current) –End (get-date $item.end.dateTime);
$timeexpire = [int]$timespan.TotalMinutes;
Write-Host "Minutes to expire reservation: "$timeexpire;
$Timers = Get-IniFile ..\ini\Timers.ini;
$WarningBeforeExp = $Timers.Timers.WarningBeforeExp_min;
if($timeexpire -le $WarningBeforeExp)
{
$msg = message(21);
Write-Host $msg;
InformationMsgBox $msg 10;
}
$proj=$item.summary
$id=$item.id
$status = (,#("reserved",$proj,$id));
Write-Host "Status in FunctionA to FunctionB: "$status
} else { $msg = "Reservation expired or schedule time mismatch."; $status = (,#("outOfTime",$msg)); }
}
} else { $msg = "You are not an attender for the current reservation for this machine."; $status = (,#("IsNotAttender",$msg));}
} else { $msg = "There is not any confirmed reservation for this machine. You can use it until someone makes a reservation."; $status = (,#("NoReservations",$msg));}
}
return $status
}
function PeriodicCheckIn ($OAuth2){
$checkin = $false
$Timers = Get-IniFile ..\ini\Timers.ini
$CheckInPeriodicity = $Timers.Timers.CheckInPeriodicity_min
for($i=1;;$i++)
{
$timeout = IdleTimeout
if(-not $timeout)
{
$funcA = CheckReservation $OAuth2
Write-Host "Status in FunctionB from FunctionA: "$funcA
$reservation = $funcA
if ($reservation[0] -match "reserved")
{
$project = $reservation[1]
$id = $reservation[2]
Write-Host "Reservation found"
Write-Host "Project: "$project
Write-Host "Id: "$id
if(-not $checkin)
{
storageData "CheckInOut" $OAuth2 "CheckIn" $project "" $false
$checkin = $true
$msg = message(15)
Write-Host $msg
InformationMsgBox $msg -1
}
else
{
storageData "updatetime" $OAuth2 "LastUpdate" $project "" $false
}
}
elseif($i -eq 1)
{
Write-Host "Reservation not found"
$Availability = CheckAvailability $OAuth2 "10"
Write-Host "Availability for now: "$Availability
if($Availability -match "Yes")
{
$msg = message(16)
$msgBoxInput = QuestionMsgBox $msg 30
if($msgBoxInput -eq 6)
{
$project = GetProject "FromUser"
CreateReservation $OAuth2 $project "10"
storageData "CheckInOut" $OAuth2 "CheckIn" $project "" $false
$checkin = $true
$msg = message(15)
Write-Host $msg
InformationMsgBox $msg -1
}
else
{
$leave = $true;
}
} else
{
$leave = $true;
}
}
else
{
Write-Host "O pau é aqui?1 $reservation[1]"
$msg = message(18, $reservation[1]);
Write-Host "O pau é aqui?2 $reservation[1]"
StopMsgBox $msg -60
$leave = $true;
}
} else {$leave = $true;}
if($leave -eq $true){ return $true}
Write-Host "CheckIn $i"
start-sleep -Seconds ([double]$CheckInPeriodicity*60)
}
}
function message($index,$txt){
$LastWarning_min = Get-IniFile ..\ini\Timers.ini
$LastWarning_min = $LastWarning_min.Timers.LastWarning_min/60
$ManualAuthTimeout_min = $LastWarning_min.Timers.ManualAuthTimeout_min
Write-Host "Next message index: $index"
$arrMessage =
"[MSG000] It is not possible to identify if this current PC is Workstation or Buildstation machine.",
"[MSG001] Shutting down the system.",
"[MSG002] You do not have approriate access to this function. Get in contact with lab support.",
"[MSG003] An error occurred. Verify if there are at least two not empty .txt file, if the path is correct or if you have write permission to the path $txt.",
"[MSG004] Attempt to delete a folder that does not exist: $txt.",
"[MSG005] Mapping failed. Make sure your connection can reach the networking that remote path ""$txt"" belongs.",
"[MSG006] Team not specified for the user $env:UserName. Please make sure the user is registered.",
"[MSG007] Connection failed. Make sure the PC can reach FIATAUTO networking then try again.",
"[MSG008] Error while Import-Module.",
"[MSG009] Error on OAuth 2.0 for Google APIs Authorization.",
"[MSG010] Error on Method: spreadsheets.values.get (writing) for Google Sheets API request.",
"[MSG011] Error on Method: spreadsheets.values.get (reading) for Google Sheets API request.",
"[MSG012] Error on Method: scripts.run for Google App Script API request.",
"[MSG013] Error on Events: get for Google Calendar API request.",
"[MSG014] Error on Events: list for Google Calendar API request.",
"[MSG015] Your access has been granted to work on the project: $global:project.",
"[MSG016] No reservation was found. Would you like to make a short reservation?",
"[MSG017] Permission to shared drives mismatch. Select OK to proceed for manual authorization within $ManualAuthTimeout_min minutes or select CANCEL for Windows logoff now.",
"[MSG018] No valid reservation found. $txt",
"[MSG019] Inactive time exceeded the inactivity limit. Select OK within 60 seconds to avoid the current Windows session logoff.",
"[MSG020] Save your files now. Shutting down the system within $LastWarning_min seconds.",
"[MSG021] Your reservation is close to expire!"
return $arrMessage[$index]
}
function InformationMsgBox($msg, $msg_timeout){
$sh = New-Object -ComObject "Wscript.Shell"
return $sh.Popup($msg,$msg_timeout,$global:AppTitle,1+64)
}
As you have noted yourself, the InformationMsgBox is to blame. Every command returning output gets added to the pipeline.
return $sh.Popup($msg,$msg_timeout,$global:AppTitle,1+64) returns the 1 you see added to your array. You can suppress it's output by sending it to Out-Null.
function InformationMsgBox($msg, $msg_timeout){
$sh = New-Object -ComObject "Wscript.Shell"
return $sh.Popup($msg,$msg_timeout,$global:AppTitle,1+64) | Out-Null
}

Find duplicate values in an array

i have the following code:
cls
Get-Module -ListAvailable | Import-Module
Import-Module ActiveDirectory
$Groups = Get-ADGroup -Filter {name -like 'XYZ'} | select name -
ExpandProperty name
$i=0
$tot = $Groups.count
$Table = #()
$Record = #{
"Group Name" = ""
"Name" = ""
"username" = ""
}
Foreach ($Group in $Groups) {
#// Set up progress bar
$i++
$status = "{0:N0}" -f ($i / $tot * 100)
Write-Progress -Activity "Exporting AD Groups" -status "Processing
Group $i of $tot : $status% Completed" -PercentComplete ($i / $tot *
100)
$Arrayofmembers = Get-ADGroupMember -identity $Group -recursive |
select name, SamAccountName
foreach ($Member in $Arrayofmembers) {
$Record."Group Name" = $Group
$Record."Name" = $Member.name
$Record."username" = $Member.SamAccountName
$objRecord = New-Object PSObject -property $Record
$Table += $objrecord
}
}
Write-Host $Table
which works perfectly but i want to list all duplicates in the $Record."Name" = $Member.name with specific group so for example:
username=barry is duplicated in GROUP XYZ
i tried already the following:
ForEach ($Element in $Table)
{
If (($Table -match $Element).count -gt 1)
{
"Duplicates detected"
}
}
The simplest answer is to just pipe $Table to Group-Object and filter for groups with a count greater than one at the end as such:
$Table | Group 'Group Name','Name' | Where{$_.Count -gt 1}
If you are looking to do this in the middle of your loop you could do so by grouping the results of Get-ADGroupMember, but I think it'll probably be faster to do it all at the end.
You could simply keep track of the members using a hashtable:
$seen = #{};
foreach ($Member in $Arrayofmembers)
{
if($seen[$Member.Name])
{
Write-Host "$($Member.Name) is duplicated in group $Group";
}
else
{
$seen.Add($Member.Name, $true);
}
# ... rest of the loop
}

How do I add Checked Items from a CheckedListBox to a Combobox (dropdown) and remove them from the Combobox when unchecked?

I should start by saying that i'm new to PowerShell and i'm still in the learning phase. I've hit a road block and any help would be appreciated.
I have the following code:
# LOAD WINFORMS ASSEMBLY
[reflection.assembly]::LoadWithPartialName( "System.Windows.Forms")
[reflection.assembly]::LoadWithPartialName( "System.Drawing")
# CREATE FORMS
$Form = New-Object Windows.Forms.Form
$Form.text = "Post-Image Configuration Tool"
$Form.Width = 900
$Form.Height = 560
$Form.BackColor = "#3a73b8"
$Form.ForeColor = "White"
$Form.FormBorderStyle = "None"
$Form.StartPosition = "CenterScreen"
# START NETWORK CONFIGURATION PAGE
$GetConnectedAdapters = Get-WmiObject -Class Win32_NetworkAdapter -Filter "NetConnectionStatus = 2" | Select-Object NetConnectionID, Name, MACAddress
$netConfigList1 = New-Object System.Windows.Forms.CheckedListBox
$netConfigList1.Location = New-Object System.Drawing.Size(310,300)
$netConfigList1.Size = New-Object System.Drawing.Size(480,180)
$netConfigList1.Height = 100
$netConfigList1.BackColor = "#3a73b8"
$netConfigList1.ForeColor = "White"
$netConfigList1.BorderStyle = "None"
$netConfigList1.Font = $ListFont
$netConfigList1.add_SelectedIndexChanged({ListNetAdapters})
$netConfigListAdapters = #()
ForEach ($i in $GetConnectedAdapters.NetConnectionID){
$GetAdapterName = Get-WmiObject -Class Win32_NetworkAdapter |Where {$_.NetConnectionID -eq $i} | Select-Object Name, NetConnectionID, MACAddress
$AdapterName = $i +" - " + "("+ $GetAdapterName.Name +")"
$netConfigListAdapters += ,$AdapterName
}
$netConfigList1.Items.AddRange($netConfigListAdapters)
$netConfigSubtext5 = New-Object Windows.Forms.Label
$netConfigSubtext5.Location = New-Object Drawing.Point 290,400
$netConfigSubtext5.Size = New-Object Drawing.Point 590,20
$netConfigSubtext5.text = "• Select the Standby Adapter:"
$netConfigSubtext5.font = $SubTextFont
$netConfigComboBox1 = New-Object System.Windows.Forms.ComboBox
$netConfigComboBox1.Location = New-Object System.Drawing.Size(310,420)
$netConfigComboBox1.Size = New-Object System.Drawing.Size(260,20)
$netConfigComboBox1.Font = $SubTextFont
$netConfigComboBox1.DropDownStyle = "DropDownList"
[void] $netConfigComboBox1.Items.Add("None (All Adapters Active)")
$NetConfiguration = $netConfigList1,$netConfigSubtext5,$netConfigComboBox1
# CREATE FUNCTIONS
Function ListNetAdapters
{
$RemoveItems = #()
$AddItems = #()
for($index =0; $index -lt $netConfigList1.Items.Count; $index++)
{
$test = $netConfigList1.Items | Where-Object { $netConfigList1.Items.IndexOf($index) }
if($netConfigList1.GetItemChecked($index) -AND $netConfigComboBox1.Items -notcontains $test)
{
$AddItems += ,$test
}
ForEach($i in $netConfigComboBox1.Items){
IF(($netConfigList1.CheckedItems -notcontains $i) -AND ($i -ne 'None (All Adapters Active)')){$RemoveItems += ,$i}
}
}
ForEach ($i in $RemoveItems){$netConfigComboBox1.Items.Remove($i)}
ForEach ($i in $AddItems){$netConfigComboBox1.Items.Add($i)}
}
Function AddNetConfiguration
{
ForEach ($i in $NetConfiguration){$form.controls.add($i)}
}
AddNetConfiguration
# DISPLAY FORM
$form.ShowDialog()
Basically, what i'm trying to accomplish is exactly what you would see in the Advanced Settings of a NIC Team in Windows Server 2012/2012 R2. I want the network adapters selected in the CheckedListBox to populate in the ComboBox and be removed if unchecked.
I've installed WMF 4.0 on my Windows 7 PC and this seems to work well, but I get "System.Object[]" in Windows Server 2012. So i'm apparently missing the big picture or doing something wrong.
Windows Server 2012 comes with PowerShell v3.0, you have to make it to WMF4.0
Answer moved from question by editor
I was able to get it working after I fixed the $ListNetAdapters function. I think I was over complicating it before.
Function ListNetAdapters
{
$RemoveItems = #()
$AddItems = #()
ForEach($checkedItem in $netConfigList1.CheckedItems){
IF($netConfigComboBox1.Items -notcontains $checkedItem){$AddItems += ,$checkedItem}
}
ForEach($item2Badded in $AddItems){$netConfigComboBox1.Items.Add($item2Badded)}
ForEach($dropdownItem in $netConfigComboBox1.Items){
IF($netConfigList1.CheckedItems -notcontains $dropdownItem){$RemoveItems += ,$dropdownItem}
}
ForEach($item2Bremoved in $RemoveItems){
IF($item2Bremoved -ne 'None (All Adapters Active)'){$netConfigComboBox1.Items.Remove("$item2Bremoved")}
}
}

Easy way to List info from arrays

I have the code below which checks the registry for entries (more than 20 of them) and if it doesn't exists it creates a registry key and adds it to an array.
After that I need to check for all the names in the array to my other array and if it matches, I need it to pull the info from my second array and show it on the screen(the log location, registry location etc). But Can't really figure out how to match the array and write in on the screen without writing very long if statements.
Does anyone know a good way of doing this?
Thanks in advance!
$Reg = "HKLM:\Software\"
$NeedtoCheck = #()
$testing = #("Test1Name","Test2Name", "Test3Name")
$allTests = #(
$Test1 = #{
Name = "Test1"
Logfile = "C:\Checking\test1.log"
Version = "16"
RegName = "test1Nameinfo*"
Installname = "InstallTest1"
UninstallName = "UninstallTest1"
},
$Test2 = #{
Name = "Test"
Logfile = "C:\test2.log"
Version = "7"
RegName = "test2Nameinfo*"
Installname = "InstallTest2"
UninstallName = "UninstallTest2"
},
$Test3 = #{
Name = "Test3"
Logfile = "C:\Temp\Checkhere\test3.log"
Version = "99"
RegName = "test3Nameinfo*"
Installname = "InstallTest3"
UninstallName = "UninstallTest3"
}
$Test1Name = $Test1.name
$Test1Logfile = $Test1.Logfile
$Test1Version = $Test1.Version
$Test1RegName = $Test1.RegName
$Test1Install = $Test1.InstallName
$Test1Uninstall = $Test1.UninstallName
$Test2Name = $Test2.name
$Test2Logfile = $Test2.Logfile
$Test2Version = $Test2.Version
$Test2RegName = $Test2.RegName
$Test2Install = $Test2.InstallName
$Test2Uninstall = $Test2.UninstallName
$Test3Name = $Test3.name
$Test3Logfile = $Test3.Logfile
$Test3Version = $Test3.Version
$Test3RegName = $Test3.RegName
$Test3Install = $Test3.InstallName
$Test3Uninstall = $Test3.UninstallName
Foreach($Test in $testing){
$Key = (Get-Item "Reg").getvalue("$Test")
IF($Key -eq $null)
{
New-Itemproperty -path "HKLM:\Software\" -value "Check" -PropertyType string -name $Test -Force -ErrorAction SilentlyContinue
Write-Host "$Test created"
$Needtocheck += $Test
}
ELSEIF($key -eq "Check")
{
$Needtocheck += $Test
}
ELSE
{
Write-Host "$Test already Checked"
}
}
Foreach($item in $NeedtoCheck)
{
If($item -match $Test1Name)
{
Write-Host "$Test1Name info"
Write-host "$Test1Name`
$Test1Logfile`
$Test1Version`
$Test1RegName`
$Test1Install`
$Test1Uninstall`
}
Else
{
Write-Host "Not in the list"
}
}
....
This code doesn't make a lot of sense to be honest. If you want 20 checks to be setup, and then only run certain checks, then that's fine, but you really don't need additional cross checking to reference one array against another array, and redefining things like you do when you assign variables for each values in each hashtable. Personally I'd make objects not hashtables, but that's me. Actually, probably even better, make a hashtable with all available tests, then for the value make an object with the properties that you need. Oh, yeah, that'd be the way to go, but would need a little re-writing. Check this out...
$Reg = 'HKLM:\Software\'
$NeedtoCheck = #()
$testing = #('Test2','Test1','NotATest')
#Define Tests
$AllTests = #{'Test1' = [PSCustomObject]#{
Name = "Test1"
Logfile = "C:\Checking\test1.log"
Version = "16"
RegName = "test1Nameinfo*"
Installname = "InstallTest1"
UninstallName = "UninstallTest1"
}
'Test2' = [PSCustomObject]#{
Name = "Test"
Logfile = "C:\test2.log"
Version = "7"
RegName = "test2Nameinfo*"
Installname = "InstallTest2"
UninstallName = "UninstallTest2"
}
'Test3' = [PSCustomObject]#{
Name = "Test3"
Logfile = "C:\Temp\Checkhere\test3.log"
Version = "99"
RegName = "test3Nameinfo*"
Installname = "InstallTest3"
UnnstallName = "UninstallTest3"
}
}
#$allTests = #($Test1,$Test2,$Test3)
Foreach($Test in $Testing){
If($Test -in $allTests.Keys){
$Key = (Get-Item $Reg).getvalue($AllTests[$Test].RegName)
Switch($Key){
#Case - Key not there
{[string]::IsNullOrEmpty($_)}{
New-Itemproperty -path "HKLM:\Software\" -value "Check" -PropertyType string -name $AllTests[$Test].RegName -Force -ErrorAction SilentlyContinue
Write-Host "`n$Test created"
Write-Host "`n$Test info:"
Write-host $allTests[$test].Name
Write-host $allTests[$test].LogFile
Write-host $allTests[$test].Version
Write-host $allTests[$test].RegName
Write-host $allTests[$test].Installname
Write-host $allTests[$test].Uninstallname
}
#Case - Key = 'Check'
{$_ -eq "Check"}{
Write-Host "`n$Test info:`n"
Write-host $allTests[$test].Name
Write-host $allTests[$test].LogFile
Write-host $allTests[$test].Version
Write-host $allTests[$test].RegName
Write-host $allTests[$test].Installname
Write-host $allTests[$test].Uninstallname
}
#Default - Key exists and does not need to be checked
default {
Write-Host "`n$Test already Checked"
}
}
}Else{
Write-Host "`n$Test not in list"
}
}
That should do what you were doing before, with built in responses and checks. Plus this doesn't duplicate efforts and what not. Plus it allows you to name tests whatever you want, and have all the properties you had before associated with that name. Alternatively you could add a member to each test run, like 'Status', and set that to Created, Check, or Valid, then you could filter $AllTests later and look for entries with a Status property, and filter against that if you needed additional reporting.
You can filter down the tests you want to check like so, if I understand what you are asking for:
$Needtocheck | Where {$_ -in $testing} |
Foreach {... do something for NeedToCheck tests that existing in $testing ... }
I had to change several pieces of the code as there were syntax errors. Guessing most were from trying to create some sample code for us to play with. I have many comments in the code but I will explain some as well outside of that.
$Reg = "HKLM:\Software\"
$testing = "Test1","Test2", "Test3"
$allTests = #(
New-Object -TypeName PSCustomObject -Property #{
Name = "Test1"
Logfile = "C:\Checking\test1.log"
Version = "16"
RegName = "test1Nameinfo*"
Installname = "InstallTest1"
UninstallName = "UninstallTest1"
}
New-Object -TypeName PSCustomObject -Property #{
Name = "Test2"
Logfile = "C:\test2.log"
Version = "7"
RegName = "test2Nameinfo*"
Installname = "InstallTest2"
UninstallName = "UninstallTest2"
}
New-Object -TypeName PSCustomObject -Property #{
Name = "Test3"
Logfile = "C:\Temp\Checkhere\test3.log"
Version = "99"
RegName = "test3Nameinfo*"
Installname = "InstallTest3"
UninstallName = "UninstallTest3"
}
)
$passed = $testing | ForEach-Object{
# Changed the for construct to better allow output. Added the next line to make the rest of the code the same.
$test = $_
$Key = (Get-Item $Reg).getvalue($Test)
If($Key -eq $null){
# New-Itemproperty creates output. Cast that to void to keep it out of $passed
[void](New-ItemProperty -path "HKLM:\Software\" -value "Check" -PropertyType string -name $Test -Force -ErrorAction SilentlyContinue)
Write-Host "$Test created"
# Send this test to output
Write-Output $Test
} Elseif ($key -eq "Check")
{
# Send this test to output
Write-Output $Test
} Else {
Write-Host "$Test already Checked"
}
}
$allTests | Where-Object{$passed -contains $_.Name}
We run all the values in $testing and if one is created or already "Checked" then we send it down the pipe where it populates the variable $passed. The we take $allTests and filter out every test that has a match.

Resources