Powershell fastest way to merge two arrays using a common property? - performance

What's the fastest way to merge two arrays using a common property?
Users | Select *
Username : Joe.Doe
Office : Chicago
Email :
Username : Mike.Smith
Office : New York
Email :
...
UserEmails | Select *
AccountEmail : Mike.Smith
EmailAddress : mike-smith#example.com
AccountEmail : Joe.Doe
EmailAddress : jsmith12#example.com
...
The merge should result in:
UsersCompleteList | Select *
Username : Joe.Doe
Office : Chicago
Email : jsmith12#example.com
Username : Mike.Smith
Office : New York
Email : mike-smith#example.com
...
Something like for each ($user in $users) { ($user.Email = $userEmails | ? { $_.AccountEmail -eq $user.Username}).EmailAddress takes ages on large datasets.

Loop through one collection and store the values in a hash. Then loop through the other collection and pull the value back out of the hash. Something like:
$hash = #{}
$userEmails | %{ $hash[$_.AccountEmail] = $_.EmailAddress }
$users | %{ $_.Email = $hash[$_.Username] }
If you have other properties you can just store the original object:
$hash = #{}
$userEmails | %{ $hash[$_.AccountEmail] = $_ }
$users | %{
$item = $hash[$_.Username]
$_.Email = $item.EmailAddress
$_.Other = $item.SomethingElse
}
Or with loops instead of ForEach-Object including:
$hash = #{}
foreach($e in $userEmails) {
$hash[$e.AccountEmail] = $e
}
foreach($u in $users) {
$item = $hash[$u.UserName]
if ($item -ne $null) {
$u.Email = $item.EmailAddress
}
}

Related

How to create query for google bar chart in laravel?

This is bar graph i want to draw and i am struck in queries
My Database look like where i want to show population of country of 2020 Year
id | country_name | population | created_at
1 | USA | 2000000000 | 2020-02-04
2 | China | 2200000000 | 2020-02-04
3 | Russia | 12000000 | 2020-04-02
My Query look like this. I am just trying to build query but not getting result.Maybe there are some mistake.At first i making $countries variable to get all countries.
public function barChart(){
$countries=Country::get();
$graphic_header=['Year'];
$countrydata=[];
$actionDate=[];
$country_name=[];
foreach ($countries as $country) {
array_push($country_name, $country->name);
array_push($actionDate, date('Y', strtotime($country->created_at)));
$actionDate = array_unique($actionDate);
}
$graphic_header=array_merge($graphic_header,$country_name); //Dynamic Header
array_push($countrydata,$graphic_header);
foreach($actionDate as $d) {
$d = [$d];
$d = array_pad($d, sizeof($graphic_header), 0);
array_push($data, $d);
}
foreach ($countries as $country){
$date = date('Y', strtotime($country->created_at));
foreach ($data as $in =>$gd){
if ($date == $gd[0]) {
$index = (array_search($country->country_name, $graphic_header));
$country_data[$in][$index] = $country->population;
}
}
}
return response()->json([
'data'=> $country_data,
]);
}
simply use this groupBy collection method
$countries=Country::get();
$countries = $countries->groupBy('country_name');
$countries->toArray();

Get the domain name of the user of ADSI object?

In the following script, it will print all the users of the groups. However, the domain name is missing (Some users are in different Windows domain)?
$computer = [ADSI]"WinNT://$server,computer"
$computer.psbase.children | ? {
$_.psbase.schemaClassName -eq 'group'
} | % {
$gn = $_.name.ToString()
write-host $gn
write-host "------"
$group =[ADSI]$_.psbase.Path
$group.psbase.Invoke("Members") | % {
$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
}
}
Try fetching the SID instead of the name and translate that back to a username:
$computer.psbase.children | ? {
$_.psbase.schemaClassName -eq 'group'
} | % {
$gn = $_.name.ToString()
write-host $gn
write-host "------"
$group =[ADSI]$_.psbase.Path
$group.psbase.Invoke("Members") | % {
$bytes = $_.GetType().InvokeMember('objectSid', 'GetProperty', $null, $_, $null)
$sid = New-Object Security.Principal.SecurityIdentifier ($bytes, 0)
$sid.Translate([Security.Principal.NTAccount])
}
}
The result should include the computer or domain name.
We have a similar issue where there are accounts from different domains on the computers and we need the domain back. Unfortunately the SID fetch doesn't work I think for local accounts and the domains the computer used to be joined to in some cases, so it didn't return all results.
This was the best solution I found for us:
Admin = $_.GetType().InvokeMember("AdsPath", 'GetProperty', $null, $_, $null)
will return results like
WinNT://#domain#/#account#
or WinNT://#domain of computer#/#computer-name#/#account#
for local accounts
$servers= get-content 'C:\temp\work\localadmins\serverlist_in.txt'
$output = 'C:\temp\work\localadmins\serverlist_out.csv'
$results = #()
foreach($server in $servers)
{
$admins = #()
$group =[ADSI]"WinNT://$server/Administrators"
$members = #($group.psbase.Invoke("Members"))
$members | foreach {
$obj = new-object psobject -Property #{
Server = $Server
Admin = $_.GetType().InvokeMember("AdsPath", 'GetProperty', $null, $_, $null)
}
$admins += $obj
}
$results += $admins
}
$results | Export-csv $Output -NoTypeInformation

How to add an embedded image to a script?

I am completely stumped. I am trying to add an embedded image to a notification email. The only scripts i can find are using .net to create a new email object.Can this only be done using .net to create an email object? Any Ideas
#################################################
# Configure the following variables….
# expireindays1 + 2 = At what count of days left on a password do you want a notification?
$smtpServer=”smtprelay.domain.com”
$expireindays1 = 5
#$expireindays2 = 1
$from = “Technology Helpdesk <technologyhelpdesk#domain.com>”
#################################################
#Get Users From AD who are enabled
Import-Module ActiveDirectory
$users = get-aduser -filter * -Properties enabled, GivenName, passwordneverexpires, passwordexpired, emailaddress, passwordlastset |where {$_.Enabled -eq “True”} | where { $_.PasswordNeverExpires -eq $false } | where { $_.passwordexpired -eq $false }
foreach ($user in $users)
{
$Name = (Get-ADUser $user | foreach { $_.Name})
$UserID = (Get-ADUser $user -Properties *).Samaccountname
$emailaddress = $user.emailaddress
$passwordSetDate = (get-aduser $user -properties passwordlastset | foreach { $_.PasswordLastSet })
$PasswordPol = (Get-AduserResultantPasswordPolicy $user)
# Check for Fine Grained Password
if (($PasswordPol) -ne $null)
{
$maxPasswordAge = ($PasswordPol).MaxPasswordAge
}
else
{
$maxPasswordAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge
}
$expireson = $passwordsetdate + $maxPasswordAge
$today = (get-date)
$daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days
#$subject=
$body = #'
#<html>
<body>
<img src="cid:image1"><br>
<b>$UserID : Your password will expire soon</b>
<br>
<br>
<br>
Dear $name,<br>
Your password will expire in $daystoexpire days. Please change your password before it expires to avoid password related problems. .<br>
<br>
<br>
<b>Password complexity rules:<br>
<br>
- Must be 7 or 8 characters long<br>
- Must contain at least 1 uppercase letter<br>
- Must contain at least 1 lowercase letter<br>
- Must contain at least 1 number<br>
- Must NOT contain repeating characters (e.g., aa, 11)</b><br>
<br>
<br>
Please use the following steps to change your password:<br>
- Press CTRL+ALT+DEL<br>
- Click Change a password…<br>
- Verify your User ID is correct, then type in your old and new passwords (you cannot use previously used passwords)<br>
- After the change is complete, you will be prompted that your password has been changed<br>
- If you have a Blackberry, iPhone, or iPad, those devices will need your new password as soon as your password has been changed<br>
<br>
If you have questions, or need assistance updating your passwords, please contact the Technology Help Desk. <br>
</body>
#</html>
'#
if (($daystoexpire -eq $expireindays1))
# -or ($daystoexpire -eq $expireindays2))
{
#Send-Mailmessage -smtpServer $smtpServer -from $from -to user#domain.com -subject $subject -body $body -bodyasHTML -priority High
####################################################################################################################
$images = #{
image1 = "c:\temp\action needed.png"
}
$params = #{
InlineAttachments = $images
#Attachments = 'C:\temp\action needed.png'
Body = $body
BodyAsHtml = $true
Subject = ”Your password will expire in $daystoExpire days”
From = "Technology Helpdesk <technologyhelpdesk#domain.com>"
To = 'user#domain.com'
#Cc = 'recipient2#domain.com', 'recipient3#domain.com'
SmtpServer = 'smtprelay.domain.com'
}
Send-MailMessage #params
}
}
This code does not use the dot net classes. I hope it helps.
$images = #{
image1 = 'c:\temp\test.jpg'
image2 = 'C:\temp\test2.png'
}
$body = #'
<html>
<body>
<img src="cid:image1"><br>
<img src="cid:image2">
</body>
</html>
'#
$params = #{
InlineAttachments = $images
Attachments = 'C:\temp\attachment1.txt', 'C:\temp\attachment2.txt'
Body = $body
BodyAsHtml = $true
Subject = 'Test email'
From = 'username#gmail.com'
To = 'recipient#domain.com'
Cc = 'recipient2#domain.com', 'recipient3#domain.com'
SmtpServer = 'smtp.gmail.com'
Port = 587
Credential = (Get-Credential)
UseSsl = $true
}
Send-MailMessage #params
BTW all credit to David Wyatt who created the code. He seems to be a good resource on powershell script.

How to make dynamic drop down in php?

I want to make a dynamic drop down in CI.I had done it in CI by directly passing the values from model With its design by concatenation the html.. But now i want it without the html i.e. the function just only should return the array ...
my before function was something like this...
function category() {
$sql = $this->db->query("select * from ss_category where parent_id='0'");
$result = $sql->result();
//print_r($result);die();
$output = array();
foreach ($result as $ra) {
$output=$this->get_child($ra->cat_id);
}
//print_r($output);die();
return $output;
}
function get_child($parent_id) {
//echo "select * from ss_category where parent_id=" . $parent_id;
$sql = $this->db->query("select * from ss_category where parent_id=" . $parent_id);
$r = $sql->result();
if (!empty($r)) {
foreach ($r as $s) {
$this->get_child($s->cat_id);
}
//print_r($child);
}
//print_r($r);
}
I want to make drop down something like this..
-parent 1
-child 1
-subchild 1
-child 2
-child 3
-subchild 1
-parent 2
-child 1
My table structure is like this..
+---------------------------------------------------------------+
| cat_id category_name cat_slug parent_id level description |
+---------------------------------------------------------------+
| 1 Elecotronics Electronics 1 description |
+---------------------------------------------------------------+
function parent_sort($categories)
{
foreach($categories as $item)
$childs[$item->parent_id][] = $item;
foreach($categories as $item)
if (isset($childs[$item->category_id]))
$item->childs = $childs[$item->category_id];
return $childs[0];
}

Users and Local Groups Report using Powershell?

Is there a simple way using powershell to show all Local Windows Groups that are active on a machine and the users that are part of those groups? A second part of this question would be if it can be extended to look at more than one machine at a time.
In fact you can with the ADSI type shortcut and the WinNT moniker. Here's an example to list groups and members from your own machine:
$server="."
$computer = [ADSI]"WinNT://$server,computer"
$computer.psbase.children | where { $_.psbase.schemaClassName -eq 'group' } | foreach {
write-host $_.name
write-host "------"
$group =[ADSI]$_.psbase.Path
$group.psbase.Invoke("Members") | foreach {$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}
write-host
}
Powershell does not have any inherent support for such a feature. However it's easy to wrap the "net localgroup" command with a couple of powershell functions and thus enable it in the pipeline.
Get Local Groups
function Get-LocalGroups() {
net localgroup | ?{ $_ -match "^\*.*" } | %{ $_.SubString(1) };
}
Get Local Group members
function Get-LocalGroupMembers() {
param ([string]$groupName = $(throw "Need a name") )
$lines = net localgroup $groupName
$found = $false
for ($i = 0; $i -lt $lines.Length; $i++ ) {
if ( $found ) {
if ( -not $lines[$i].StartsWith("The command completed")) {
$lines[$i]
}
} elseif ( $lines[$i] -match "^----" ) {
$found = $true;
}
}
}
Below is an improved version of Shay Levy's script which works for local groups with "orphaned" accounts which SIDs can't be resolved.
$server = "$env:COMPUTERNAME"
$computer = [ADSI]"WinNT://$server,computer"
$computer.psbase.children | where { $_.psbase.schemaClassName -eq 'group' } | foreach {
write-host $_.name
write-host "------"
$group =[ADSI]$_.psbase.Path
$group.psbase.Invoke("Members") | foreach {$_."GetType".Invoke().InvokeMember("Name", 'GetProperty', $null, $_, $null)}
write-host
}
Jay Levy's answer turned into a function :)
Function Get-LocalGroupMembers
{
Param(
[string]
$server = "."
)
Try
{
$computer = [ADSI]"WinNT://$( $Server ),computer"
$computer.psbase.children |
where {
$_.psbase.schemaClassName -eq 'group'
} |
ForEach {
$GroupName = $_.Name.ToString()
$group =[ADSI]$_.psbase.Path
$group.psbase.Invoke("Members") |
foreach {
$memberName = $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null) -replace "WinNT:", ""
$props = #{
"LocalGroup" = $GroupName
"MemberName" = $memberName
}
$obj = New-Object -TypeName psobject -Property $props
Write-Output $obj
} # foreach members
} # foreach group
}
Catch
{
Throw
}
}
To get the local group members
Get-LocalGroupMembers
To get the local group members for another machine
Get-LocalGroupMembers -Server $Computer

Resources