How to return a reference value with a method from an extended Powershell object? - powershell-5.0

I'm trying to extend a Powershell object with a method that
returns a true or false to indicate success
outputs a value by reference ([ref])
I have in my module MyExtensions.psm1.
Update-TypeData -TypeName [MyType] -MemberType ScriptMethod -memberName TryGetValue -force -value `
{
param(
$myInput,
[ref]$myOutput
)
try
{
# do something with $myInput
$myOutput = …
return $true
}
catch
{
return $false
}
}
The goal is to be able to write in a script or in another module:
Import-Module MyExtensions
$myInput = …
$value = $null
if($myTypeItem.TryGetValue($myInput, $value)
{
# I know that the $value is good
}

Using argument by reference (you just miss $myOutput.Value ="")
function addition ([int]$x, [int]$y, [ref]$R)
{
$Res = $x + $y
$R.value = $Res
}
$O1 = 1
$O2 = 2
$O3 = 0
addition $O1 $O2 ([ref]$O3)
Write-Host "values from addition $o1 and $o2 is $o3"
A more comple answer here.

Related

TYPO3 Repository outside controller

I am using TYPO3 10.4.15 and try to write a TcaProcFunc for my own extension.
namespace HGA\Album\UserFunc;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use HGA\Album\Domain\Repository\AlbumRepository;
use HGA\Album\Domain\Model\Album;
use TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface;
class TcaProcFunc
{
/**
* #param array $config
*
*/
public function getLink(&$config)
{
$ret = [];
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
$albumRepository= $objectManager->get(AlbumRepository::class);
$albums = $albumRepository->findAll();
foreach ($albums as $album){
$ret[] = ["Test1","Test1"];
}
$i = count($albums);
error_log("Album: " . $i, 0 );
$ret[] = ["Test", "Test"];
$config['items'] = $ret;
// error_log("UserFunc: " . var_export($config, true), 0);
}
}
The problem is, that findall() does not provide any result. $albumsis empty, but there is one record inside the database.
HGA is my vendor name and Album the extension name. The TcaProcFunc is in generell is working, but I don't have any access to the extension database.
Can anybody tell me, what is wrong with my code or how I what I can do to findthe problem?
Thank you in advance.
Finally I did it with ConnectionPool
namespace HGA\Album\UserFunc;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Core\Database\ConnectionPool;
class TcaProcFunc
{
/**
* #param array $config
*
*/
public function getLink(&$config)
{
$ret = [];
$albums = GeneralUtility::makeInstance(ConnectionPool::class)
->getConnectionForTable('tx_album_domain_model_album')
->select(
['uid', 'album_artist', 'album'],
'tx_album_domain_model_album',
[]
)->fetchAll();
foreach ($albums as $album){
$ret[] = [$album['album_artist'] . ": " . $album['album'], $album['uid']];
}
$config['items'] = $ret;
}
}

Date Variable is not Carry Over to Function for Query String

I receive this error:
ExecuteSqlQuery : Must declare the scalar variable "#date".
I call the query as such: ExecuteSqlQuery -server "sqlbox" -database "dbname" and I receive the date variable error. You can see my query statement uses the variable m.created_date >= #date.
How do I correctly pass the date variable to query string so it runs in the function without an issue? NOTE: the code works when I hardcode the date value.
Function ExecuteSqlQuery {
Param(
[Parameter(Mandatory=$true)][string]$server,
[Parameter(Mandatory=$true)][string]$database
)
Process
{
$date= $((get-date).AddSeconds(-120).ToString("MM-dd-yyyy HH:mm:ss"))
$getscriptinfo = "select m.created_date, a.engine_full_hierarchy as Location, e.exciter_name, e.engine_exciter_id as ExciterID, m.additional_data as ReasonDown from HugsAdminAmador.mv_audit m, HugsAdminAmador.exciter e, HugsAdminAmador.area_map a where m.object_id = e.exciter_id and e.area_map_id = a.area_map_id and m.created_date >= #date and m.additional_data like '%NewStatus=DOWN%' and m.additional_data not like '%autonomous%'"
$scriptscon = New-Object System.Data.SqlClient.SqlConnection
$scriptscon.ConnectionString = "Data Source=$server;Initial Catalog=$database;Integrated Security=true"
$scriptcmd = New-Object System.Data.SqlClient.SqlCommand
$scriptcmd.Connection = $scriptscon
$scriptcmd.CommandText = $getscriptinfo
$scriptcmd.CommandTimeout = 0
$ErrorActionPreference = 'Stop'
try
{
$scriptscon.Open()
$Reader = $scriptcmd.ExecuteReader()
# if reader returns data create an array of the error data for the potential alert.
If ($Reader.HasRows) {
$obj = $Reader | foreach {
$row = $_;
#the left naming is for the column headers in the email.
new-object psObject -Property #{
CreateDate = $row.Item("created_date")
ReasonDown = $row.Item("ReasonDown")
ObjectID = $row.Item("object_id")
}
}
}
return $obj
}
catch [Exception]
{
# Write-Warning "Get-ExecuteScripts (Connection: [$server].[$database])"
# Write-Warning $_.Exception.Message
# Write-Warning "Query: $getscriptinfo --Id $scriptid"
Write-Error $_
$ErrorEvent = #{
LogName = 'Exciter_Log'
Source = 'Exciter_Health'
EventID = 333
EntryType = 'Information'
Message = $_
}
Write-EventLog #ErrorEvent
}
finally
{
$ErrorActionPreference = 'Continue'
$scriptscon.Dispose()
$scriptcmd.Dispose()
}
}
}

Powershell incremental number at start of string

Attempting to increment the start of a string with a number.
foreach ($var in $variables) {
New-EventLog -computername $PC -LogName $var -source $var
}
I wish to increment $var with a number, so the result is like so:
$var = 1Server
$var = 2Server
etc etc.
How do I add in incremental number at the beginning of $var in my foreach statement?
I tried with:
$a = 1
foreach ($var in $variables) {
New-EventLog -computername $PC -LogName ($a++, $var) -source $var
}
But no dice.
You can use the format operator -f to insert the value of $a in the parameter for the Logname
$a = 1
foreach ($var in $variables) {
New-EventLog -computername $PC -LogName ("{0}$var" -f $a++) -source $var
}

Retrieving a int value from database

I am trying to get sender_id and receiver_id into my variables but it is giving me following error
Warning: mysql_fetch_array() expects parameter 1 to be resource,
object given in /opt/lampp/htdocs/Task/php/insertdatanew.php on line
36
Warning: mysql_fetch_row() expects parameter 1 to be resource, object
given in /opt/lampp/htdocs/Task/php/insertdatanew.php on line 42 N
CODE:
<?php
$sender_id = 0;
$receiver_id = 0;
session_start();
if(isset($_SESSION['login_user'])) {
//header('location: chat.php');
}
else {
header('location: chatlogin.php');
}
if(isset($_REQUEST['sender']) AND isset($_REQUEST['msg']) AND isset($_REQUEST['time']) AND isset($_REQUEST['receiver']) ){
$msg = $_REQUEST['msg'];
$time = $_REQUEST['time'];
$sender = $_REQUEST['sender'];
$receiver = $_REQUEST['receiver'];
echo $sender;
echo $receiver;
echo $msg;
echo $time;
//echo $msg;
if ( empty($_REQUEST['msg']) ) {
}
else{
require_once 'dc_chat.php';
$mysqli = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
$result = $mysqli -> query("SELECT id from users where username LIKE '{$sender}'");
$row = mysql_fetch_row($result);
$sender_id = $row[0];
$result = $mysqli -> query("SELECT id from users where username LIKE '{$receiver}'");
$row = mysql_fetch_row($result);
$receiver_id = $row[0];
//echo $receiver_id;
$sql = $mysqli -> query("INSERT INTO `messages` (`sender_id`, `receiver_id`, `msg`, 'chattime') VALUES ('{$sender_id}', '{$receiver_id}', '{$msg}' ,'{$time}')");
if(! $sql ) {
echo 'N';
}
else {
echo 'Y';
}
}
}
else{
echo "hello";
}
?>
I am getting $msg, $time, $sender, $receiver from a ajax and datatype is JSON
You are mixing mysql and mysqli functions. mysql_fetch_row should probably be mysqli_fetch_row.
Replace if (!$sql) with if ($mysqli->affected_rows == 0) to test for success on the INSERT statement.
If you suspect an error in your SQL statement use echo $mysqli->error; after your query line to put that on the screen.

how to edit .htpasswd using php?

i have a protected directory where only user on .htpasswd can access, but sometimes it requires the user to change password or username, edit a specific username password to his username him self
sample users
kevien : kka
mike : mike
And let say i want to change kevien to XYZ
And same thing goes to password
I have modified function to use all types of crypt alghoritms. Someone may find it useful:
/*
Function change password in htpasswd.
Arguments:
$user > User name we want to change password to.
$newpass > New password
$type > Type of cryptogrphy: DES, SHA, MD5.
$salt > Option: Add your custom salt (hashing string).
Salt is applied to DES and MD5 and must be in range 0-9A-Za-z
$oldpass > Option: Add more security, user must known old password to change it.
This option is not supported for DES and MD5 without salt!!!
$path > Path to .htaccess file which contain the password protection.
Path to password file is obtained from this .htaccess file.
*/
function changePass($user, $newpass, $type="SHA", $salt="", $oldpass="", $path=".htaccess")
{
switch ($type) {
case "DES" :
$salt = substr($salt,0,2); // Salt must be 2 char range 0-9A-Za-z
$newpass = crypt($newpass,$salt);
if ($oldpass != null) {
$oldpass = crypt($oldpass,$salt);
}
break;
case "SHA" :
$newpass = '{SHA}'.base64_encode(sha1($newpass, TRUE));
if ($oldpass != null) {
$oldpass = '{SHA}'.base64_encode(sha1($oldpass, TRUE));
}
break;
case "MD5" :
$salt = substr($salt,0,8); //Salt must be max 8 char range 0-9A-Za-z
$newpass = crypt_apr1_md5($newpass, $salt);
if ($oldpass != null) {
$oldpass = crypt_apr1_md5($oldpass, $salt);
}
break;
default:
return false;
break;
}
$hta_arr = explode("\n", file_get_contents($path));
foreach ($hta_arr as $line) {
$line = preg_replace('/\s+/','',$line); // remove spaces
if ($line) {
$line_arr = explode('"', $line);
if (strcmp($line_arr[0],"AuthUserFile") == 0) {
$path_htaccess = $line_arr[1];
}
}
}
$htp_arr = explode("\n", file_get_contents($path_htaccess));
$new_file = "";
foreach ($htp_arr as $line) {
$line = preg_replace('/\s+/', '', $line); // remove spaces
if ($line) {
list($usr, $pass) = explode(":", $line, 2);
if (strcmp($user, $usr) == 0) {
if ($oldpass != null) {
if ($oldpass == $pass) {
$new_file .= $user.':'.$newpass."\n";
} else {
return false;
}
} else {
$new_file .= $user.':'.$newpass."\n";
}
} else {
$new_file .= $user.':'.$pass."\n";
}
}
}
$f = fopen($path_htaccess,"w") or die("couldn't open the file");
fwrite($f, $new_file);
fclose($f);
return true;
}
Function for generating Apache like MD5:
/**
* #param string $password
* #param string|null $salt
* #ref https://stackoverflow.com/a/8786956
*/
function crypt_apr1_md5($password, $salt = null)
{
if (!$salt) {
$salt = substr(base_convert(bin2hex(random_bytes(6)), 16, 36), 1, 8);
}
$len = strlen($password);
$text = $password . '$apr1$' . $salt;
$bin = pack("H32", md5($password . $salt . $password));
for ($i = $len; $i > 0; $i -= 16) {
$text .= substr($bin, 0, min(16, $i));
}
for ($i = $len; $i > 0; $i >>= 1) {
$text .= ($i & 1) ? chr(0) : $password[0];
}
$bin = pack("H32", md5($text));
for ($i = 0; $i < 1000; $i++) {
$new = ($i & 1) ? $password : $bin;
if ($i % 3) {
$new .= $salt;
}
if ($i % 7) {
$new .= $password;
}
$new .= ($i & 1) ? $bin : $password;
$bin = pack("H32", md5($new));
}
$tmp = '';
for ($i = 0; $i < 5; $i++) {
$k = $i + 6;
$j = $i + 12;
if ($j == 16) {
$j = 5;
}
$tmp = $bin[$i] . $bin[$k] . $bin[$j] . $tmp;
}
$tmp = chr(0) . chr(0) . $bin[11] . $tmp;
$tmp = strtr(
strrev(substr(base64_encode($tmp), 2)),
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
);
return "$" . "apr1" . "$" . $salt . "$" . $tmp;
}
Demo of crypt_apr1_md5() is available here.
Note that as of Apache 2.4, bcrypt is supported, so you can (and SHOULD) just use password_hash() on newer versions of Apache for this purpose.
Ofc this is just a sample, that will read your current file, find the given username and change either it is password of username.
Please keep in mind that this code is not safe and you would still need to parse the username and password so it does not break your file.
$username = $_POST['user'];
$password = $_POST['pass'];
$new_username = $_POST['newuser'];
$new_password = $_POST['newpass'];
$action = $_POST['action'];
//read the file into an array
$lines = explode("\n", file_get_contents('.htpasswd'));
//read the array and change the data if found
$new_file = "";
foreach($lines as $line)
{
$line = preg_replace('/\s+/','',$line); // remove spaces
if ($line) {
list($user, $pass) = split(":", $line, 2);
if ($user == $username) {
if ($action == "password") {
$new_file .= $user.':'.$new_password."\n";
} else {
$new_file .= $new_username.':'.$pass."\n";
}
} else {
$new_file .= $user.':'.$pass."\n";
}
}
}
//save the information
$f=fopen(".htpasswd","w") or die("couldn't open the file");
fwrite($f,$new_file);
fclose($f);
Don't. Store your authdb in a database instead, via e.g. mod_auth_mysql.
Googled "php generate htpasswd", got this article: How to create a password for a .htpasswd file using PHP.
The key line seems to be:
$password = crypt($clearTextPassword, base64_encode($clearTextPassword));
So I imagine you'd read in the file contents with file_get_contents, parse it into an associative array, modify the relevant entries (encrypting the password as shown above), write the array back into a string, and use file_put_contents to write the file back out.
This is most definitely not standard practice, however. Sounds like the job for a database. If you feel weird about setting up a whole database server, and your host supports it, SQLite might be a good choice.
Just in case someone is just looking for a working script, here is a solution.
It is the script published here by Kavoir with a minor change: http://www.kavoir.com/backyard/showthread.php?28-Use-PHP-to-generate-edit-and-update-htpasswd-and-htgroup-authentication-files
<?php
/*
$pairs = array(
'username' = 'password',
);
*/
// Algorithm: SHA1
class Htpasswd {
private $file = '';
public function __construct($file) {
if (file_exists($file)) {
$this -> file = $file;
} else {
return false;
}
}
private function write($pairs = array()) {
$str = '';
foreach ($pairs as $username => $password) {
$str .= "$username:{SHA}$password\n";
}
file_put_contents($this -> file, $str);
}
private function read() {
$pairs = array();
$fh = fopen($this -> file, 'r');
while (!feof($fh)) {
$pair_str = str_replace("\n", '', fgets($fh));
$pair_array = explode(':{SHA}', $pair_str);
if (count($pair_array) == 2) {
$pairs[$pair_array[0]] = $pair_array[1];
}
}
return $pairs;
}
public function addUser($username = '', $clear_password = '') {
if (!empty($username) && !empty($clear_password)) {
$all = $this -> read();
// if (!array_key_exists($username, $all)) {
$all[$username] = $this -> getHash($clear_password);
$this -> write($all);
// }
} else {
return false;
}
}
public function deleteUser($username = '') {
$all = $this -> read();
if (array_key_exists($username, $all)) {
unset($all[$username]);
$this -> write($all);
} else {
return false;
}
}
public function doesUserExist($username = '') {
$all = $this -> read();
if (array_key_exists($username, $all)) {
return true;
} else {
return false;
}
}
private function getHash($clear_password = '') {
if (!empty($clear_password)) {
return base64_encode(sha1($clear_password, true));
} else {
return false;
}
}
}
You can use this script like:
$htp = new Htpasswd('.htpasswd');
$htp -> addUser('username1', 'clearpassword1'); // this will add or edit the user
$htp -> deleteUser('username1');
// check if a certain username exists
if ($htp -> doesUserExist('username1')) {
// user exists
}