I am trying to write a PowerShell script that will create a user based off of Department and Position and add them to the AD groups specific to that position. I have a function that creates the new user and attempts to join the user to a list of groups in an array.
function CreateUser{
$sam = "$first.$last";...;$pwd = ConvertTo-SecureString "password" -AsPlainText -Force
New-ADUser -Company "MyCompany" -Department $dept -Description $desc -DisplayName $dname -EmailAddress $email -GivenName $first -Office $office -Path $path -SamAccountName $sam -Surname $last -UserPrincipalName $email
foreach ($group in $groups) { if (Get-ADGroup $group) { Add-ADGroupMember $group $sam } }
}
I have another bit of code that creates the $groups array
$positions = #()
if ($dept -eq "CSR") { $positions += "CSR Rep","CSR Lead","CSR Manager" }
if ($dept -eq "IT") { $positions += "Sysadmin","Netadmin","Sqladmin" }
...
$groups = #()
if ($position -eq "CSR Rep") { $groups += "group1","group2","group3",...,"groupN" }
if ($position -eq "CSR Lead") { $groups += "group1","group2","group3","group4",...,"groupN" }
if ($position -eq "CSR Manager") { $groups += "group1","group2","group3","group4","group5",...,"groupN" }
if ($position -eq "Sysadmin") { $groups += "group6","group7",...,"groupN" }
if ($position -eq "Netadmin") { $groups += "group7","group8","group9",...,"groupN" }
if ($position -eq "Sqladmin") { $groups += "group10","group11","group12",...,"groupN" }
After I've specified which department and position the groups array is created and I call the CreateUsers function but I get errors back like it is an empty array.
Is there something I am missing with trying to pass the parameters to the function or is there a better way to accomplish this task?
Any assistance would be greatly appreciated.
Since your code does not show the function call and your function does not have any parameters defined i assume you are not passing anything to it.
Here is how to use parameters with three example parameters, one of them a String[]:
function CreateUser{
param(
[parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[string[]] $groups,
[parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[hashtable] $userInfo,
[parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[securestring] $pwd
)
New-ADUser -Company "MyCompany" -Department $userInfo.dept -Description $userInfo.desc -DisplayName $userInfo.dname -EmailAddress $userInfo.email -GivenName $userInfo.first -Office $userInfo.office -Path $userInfo.path -SamAccountName $userInfo.sam -Surname $userInfo.last -UserPrincipalName $userInfo.email
foreach ($group in $groups) { if (Get-ADGroup $group) { Add-ADGroupMember $group $userInfo.sam } }
}
To keep the number of parameters low i have consolidated the user info into a hashtable. Hashtables are key-value sets and can be created like this:
$userInfo = #{sam="sam"; dept="department"; desc="description"; ...}
To call your function correctly do something like this:
CreateUser -groups $groups -userInfo $userInfo -pwd $pwd
You can of course add more parameters. For documentation on possible definitions and validationmethods see Technet
If you're going to create functions that are going to be more than simple things that take parameters I would strongly suggest including parameters with them. Such as:
function CreateUser{
Param([Parameter(Position=0)][string]$First = $(throw "You must specify a first name"),
[Parameter(Position=1)][string]$Last = $(throw "You must specify a last name"),
[Parameter(Position=2)][string]$Desc = $(throw "You must specify a description"),
[Parameter(Position=3)][string]$Dept = $(throw "You must specify a department"),
[Parameter(Position=4)][string]$Office = $(throw "You must specify an office"),
[Parameter(Position=5)][string]$Password = $(throw "You must specify a password"),
[string[]]$Groups
)
$sam = "$first.$last"
$pwd = ConvertTo-SecureString $Password -AsPlainText -Force
$email = "$first.$last#company.com"
$dname = "$First $Last"
$Path = "ou=$office,ou=Users,DN=company,DN=local"
New-ADUser -Company "MyCompany" -Department $dept -Description $desc -DisplayName $dname -EmailAddress $email -GivenName $first -Office $office -Path $path -SamAccountName $sam -Surname $last -UserPrincipalName $email
foreach ($group in $groups) { if (Get-ADGroup $group) { Add-ADGroupMember $group $sam } }
}
Then when you call the function you do it as such:
CreateUser "Jim" "Kirk" "Captain Extraordinaire" "Space" "$uper$ecret123" #("ExploreNewWorlds","WhereNoManHasGone")
Or you can specify arguments by name:
CreateUser -First "Jim" -Last "Kirk" -Desc "Captain Extraordinaire" -Dept "Space" -Password "$uper$ecret123" -Groups #("ExploreNewWorlds","WhereNoManHasGone")
...and while I got caught up in work trying to post this Paul beat me to it. Nice work Paul!
Edit: On a side note, I would like to introduce you to the Switch cmdlet. I think you would benefit greatly from it. While your several If statements probably do work, consider this:
Switch($position){
"CSR Rep" { $groups += "group1","group2","group3",...,"groupN";continue }
"CSR Lead" { $groups += "group1","group2","group3","group4",...,"groupN";continue }
"CSR Manager" { $groups += "group1","group2","group3","group4","group5",...,"groupN";continue }
"Sysadmin" { $groups += "group6","group7",...,"groupN";continue }
"Netadmin" { $groups += "group7","group8","group9",...,"groupN";continue }
"Sqladmin" { $groups += "group10","group11","group12",...,"groupN" }
}
That's simplistic, and in your case may not offer too much in performance improvement, but Switch offers a cleaner solution, and improved performance over several If statements. It also allows for more logic such as:
Switch($position){
{$_ -match "CSR" } { $groups += "group1", "group2" }
{$_ -match "CSR" -and -not $_ -match "Rep"} { $groups += "group3","Group4" }
}
That would add groups 1 and 2 for all CSR, and only Leads and Managers get groups 3 and 4. Anyway, just something to consider.
Related
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
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
}
I want to use a Get-ADGroup command in nested foreach loops. But somehow the command results nothing back. The command and filters are corect, as you can see it at the very bottom after the loops, the same instruction works there perfectly, for whatever reason.
$file = "\\path"
$data = Import-Csv $file -Delimiter ";" -Encoding UTF7 |
select -First 5
Measure-Command {
foreach ($item in $data ) {
$tiefe = $($item.'Tiefe')
$pfad = $($item.'Pfad')
$recht = $($item.'Recht')
$trustee = $($item.'trustee')
$LDAPDirectoryService = 'IP-Adresss'
$DomainDN = 'o=enterprise'
$LDAPFilter = "cn=$trustee"
$null = [System.Reflection.Assembly]::LoadWithPartialName('System.DirectoryServices.Protocols')
$null = [System.Reflection.Assembly]::LoadWithPartialName('System.Net')
$LDAPServer = New-Object System.DirectoryServices.Protocols.LdapConnection $LDAPDirectoryService
$LDAPServer.AuthType = [System.DirectoryServices.Protocols.AuthType]::Anonymous
$LDAPServer.SessionOptions.ProtocolVersion = 3
$LDAPServer.SessionOptions.SecureSocketLayer = $false
$Scope = [System.DirectoryServices.Protocols.SearchScope]::Subtree
$AttributeList = #('*')
$SearchRequest = New-Object System.DirectoryServices.Protocols.SearchRequest -ArgumentList $DomainDN,$LDAPFilter,$Scope,$AttributeList
$groups = $LDAPServer.SendRequest($SearchRequest)
$groups
#Prüft ob Gruppe existiert
if ($groups.Entries.Count -eq 0) {
Write-Host " Group not found!" `n -Foregroundcolor Red $LDAPFilter
#Speichert alle nicht gefundenen Gruppen zur manuellen Nachbearbeitung
Add-Content -Path \\Path -Value "$LDAPFilter"
}
foreach ($group in $groups.Entries) {
#Listet alle Member der oben übergebenen Gruppe auf
$users = $group.Attributes['member'].GetValues('string')
foreach ($user in $users) {
Write-Host $user
#Hier den User zur AD Gruppe hinzufügen
Write-Host "user zur Gruppe hinzufügen $pfad-$recht" -ForegroundColor Red
# This little Boy doesnt work
Get-ADGroup -Properties Name, Description -Filter 'Name -like "F-KT-*"' |
where {$_.Description -like "*$pfad" -and $_.Name.EndsWith($recht)}
#Add-ADGroupMember -Identity S-1-5-21-219376080-2991882224-574971396-34759 -Members $user -Whatif
}
}
}
}
# Here the command works without a fault
Get-ADGroup -Properties Name, Description -Filter 'Name -like "F-KT-*"' |
where {$_.Description -like "*$pfad" -and $_.Name.EndsWith($recht)}
I still dont know why but I found a solution working for me.
$AD = Get-ADGroup -Properties Name, Description -Filter 'Name -like "F-KT-*"' | where {$_.Description -like "*$pfad" -and $_.Name.endswith($recht) }
write-Host $AD.Name -ForegroundColor Yellow
Maybe someone can tell me why I have to declare get-ADGroup as a variable in the Loop, but outside its working without it.
I am making a script that goes into all servers we're hosting and gets all members of a specific group and the domain name, and then exports it to a file. I'm saving the users and the domain names into two arrays AA (user array) and DA (domain array) AA stands for användararray, and "användare" is users in swedish so it makes sense to me.
I noticed that the export step didn't work, no users or domain names were exported, so I tried to print them in the function. But it doesn't print anything, so I tried to print it in a different location (didn't work). After some experimenting I came to the conlusion that the only place the arrays actually contains any information is inside the foreach loop where I save the users that I find??!
Here is the code
unction GetData([int]$p) {
Write-Host("B")
for ($row = 1; $row -le $UsernamesArray.Length; $row++)
{
if($CloudArray[$row] -eq 1)
{
.
$secstr = New-Object -TypeName System.Security.SecureString
$PasswordsArray[$row].ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $UsernamesArray[$row], $secstr
$output = Invoke-Command -computername $AddressArray[$row] -credential $cred -ScriptBlock {
Import-Module Activedirectory
foreach ($Anvandare in (Get-ADGroupMember fjärrskrivbordsanvändare))
{
$AA = #($Anvandare.Name)
$DA = gc env:UserDomain
#$DA + ";" + $Anvandare.Name
$DA + ";" + $AA
}
}
$output
}
}
$DA
$AA
}
function Export {
Write-Host("C")
$filsökväg = "C:\Users\322sien\Desktop\Coolkids.csv"
$ColForetag = "Företag"
$ColAnvandare = "Användare"
$Emptyline = "`n"
$delimiter = ";"
for ($p = 1; $p -le $DomainArray.Length; $p++) {
$ColForetag + $delimiter + $ColAnvandare | Out-File $filsökväg
$DA + $delimiter + $AA | Out-File $filsökväg -Append
}
}
ReadInfo
GetData
Export
Can anyone help me with this? I've sat down with this all day and i cant find a solution.
Your variables $DA and $AA are bound to GetData function, so they live only there. You could make them available inside your script by changing it's scope.
Change this:
$AA = #($Anvandare.Name)
$DA = gc env:UserDomain
To this:
$script:AA = #($Anvandare.Name)
$script:DA = gc env:UserDomain
So they will now be available for other functions inside the script.
Also I found the ways to improve your script, hope you can see the logic:
function GetData([int]$p) {
Write-Host("B")
for ($row = 1; $row -le $UsernamesArray.Length; $row++)
{
if($CloudArray[$row] -eq 1)
{
.
$secstr = New-Object -TypeName System.Security.SecureString
$PasswordsArray[$row].ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $UsernamesArray[$row], $secstr
[array]$output = Invoke-Command -computername $AddressArray[$row] -credential $cred -ScriptBlock {
Import-Module Activedirectory
$array = #()
foreach ($Anvandare in (Get-ADGroupMember fjärrskrivbordsanvändare))
{
$object = New-Object PSObject
$object | Add-Member -MemberType NoteProperty -Name AA -Value #($Anvandare.Name)
$object | Add-Member -MemberType NoteProperty -Name DA -Value (gc env:UserDomain)
$object | Add-Member -MemberType NoteProperty -Name Something -Value $DA + ";" + $AA
$array += $object
}
Write-Output $array
}
Write-Output $output
}
}
}
Your function will now output some data.
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.