Assign Unicode Literals to PowerShell Hash Table - powershell

It's late and I am done for tonight--can someone please lend a hand on getting this to work? Do I need to do some additional work to get these Unicode strings assigned as literals?
First attempt at creating a hash table of double-encoded and desired key-value pairs:
[string] $double_encoded_values = #{
"€" = "€";
"‚" = "‚";
"Æ’" = "ƒ";
"„" = "„";
"…" = "…";
"â€" = "†";
"‡" = "‡";
"ˆ" = "ˆ";
"‰" = "‰";
"Å" = "Š";
"‹" = "‹";
"Å’" = "Œ";
"Ž" = "Ž";
"‘" = "‘";
"’" = "’";
"“" = "“";
"â€" = "”";
"•" = "•";
"–" = "–";
"—" = "—";
"Ëœ" = "˜" ;
"â„¢" = "™";
"Å¡" = "š";
"›" = "›";
"Å“" = "œ";
"ž" = "ž";
"Ÿ" = "Ÿ";
"¡" = "¡";
"¢" = "¢";
"£" = "£";
"¤" = "¤";
"Â¥" = "¥";
"¦" = "¦";
"§" = "§";
"¨" = "¨";
"©" = "©";
"ª" = "ª";
"«" = "«";
"¬" = "¬";
"®" = "®";
"¯" = "¯";
"°" = "°";
"±" = "±";
"²" = "²";
"³" = "³";
"´" = "´";
"µ" = "µ";
"¶" = "¶";
"·" = "·";
"¸" = "¸";
"¹" = "¹";
"º" = "º";
"»" = "»";
"¼" = "¼";
"½" = "½";
"¾" = "¾";
} # $double_encoded_values
My version:
PS C:\Windows\system32> $PSVersionTable.PSVersion
Major Minor Build Revision
----- ----- ----- --------
4 0 -1 -1
Error received:
At line:20 char:12
+ "–" = "–";
+ ~
Missing '=' operator after key in hash literal.
At line:20 char:12
+ "–" = "–";
+ ~
The hash literal was incomplete.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingEqualsInHashLiteral
Reference: http://www.i18nqa.com/debug/utf8-debug.html

PowerShell treats the “ in – as a double quote, effectively escaping the closing " in "–"
Use single quotes to avoid having PowerShell trying to parse the key names and values:
#{
'–' = '-'
}

Related

How to convert a string value to a dynamic data type in PowerShell?

Is it possible to assign a string value to a variable of a different type given that the data type is not known in advance? For example, in the sample below, how do I update the values of the $values hash without changing their data types:
$values = #{
"Boolean" = $true
"Int" = 5
"DateTime"= (Get-Date)
"Array" = #("A", "B", "C")
}
$stringValues = #{
"Boolean" = 'false'
"Int" = '10'
"DateTime"= '2019-01-02 14:45:59.146'
"Array" = '#("X", "Y", "Z")'
}
"INITIAL VALUES:"
foreach ($key in $values.Keys) {
($key + " = " + $values[$key] + " (" + $values[$key].GetType().FullName + ")")
}
"`nUPDATING..."
foreach ($key in $stringValues.Keys) {
$values[$key] = $stringValues[$key]
}
"`nUPDATED VALUES:"
foreach ($key in $values.Keys) {
($key + " = " + $values[$key] + " (" + $values[$key].GetType().FullName + ")")
}
OUTPUT:
INITIAL VALUES:
DateTime = 04/23/2019 16:54:13 (System.DateTime)
Array = A B C (System.Object[])
Boolean = True (System.Boolean)
Int = 5 (System.Int32)
UPDATING...
UPDATED VALUES:
DateTime = 2019-01-02 14:45:59.146 (System.String)
Array = #("X", "Y", "Z") (System.String)
Boolean = false (System.String)
Int = 10 (System.String)
I need the updated values to match the original data types and not just get converted to System.String.
I am flexible on the contents of the strings. E.g. a string holding a boolean false value may be $false/false/[boolean]false/[boolean]$false/etc or a string holding an array may use a different formatting (basically, whatever is easier to convert the string to a proper data type).
In essence, I want to simulate whatever the ConvertFrom-Json cmdlet does when it sets the object property from a JSON string, only in my case, I do not have a JSON structure.
(In case someone wonders what I'm trying to do: I am trying to add an INI file parser to my ConfigFile module, and no, I cannot just use a hash to return the INI settings; I need to load the values into the corresponding PSVariables and for this to work, I need to convert strings to proper data types.)
So you want to cast/convert the new value to the type of the old value.
The idea needs to cast from a variable,
here is a related question powershell-type-cast-using-type-stored-in-variable
The answer suggest:
You can roughly emulate a cast using the following method:
[System.Management.Automation.LanguagePrimitives]::ConvertTo($Value, $TargetType)
The following changed routine shows: it isn't that simple, especially when the new data needs overloads/other parameters in the conversion.
"UPDATING..."
foreach ($key in $stringValues.Keys) {
$values[$key] = [System.Management.Automation.LanguagePrimitives]::ConvertTo(
$stringValues[$key], $values[$key].gettype())
}
My German locale error message:
Ausnahme beim Aufrufen von "ConvertTo" mit 2 Argument(en): "Der Wert "2019-01-02 14:45.59.146" kann nicht in den Typ
"System.DateTime" konvertiert werden. Fehler: "Die Zeichenfolge wurde nicht als gültiges DateTime erkannt.""
In Zeile:2 Zeichen:5
+ $values[$key] = [System.Management.Automation.LanguagePrimitives] ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : PSInvalidCastException
And the unsufficient result:
DateTime = 04/24/2019 09:49:19 (System.DateTime)
Array = #("X", "Y", "Z") (System.Object[])
Boolean = True (System.Boolean)
Int = 10 (System.Int32)
You may elaborate yourself on this idea, handling old types/new data more individually.
You can use a custom class in lieu of a hashtable; unlike hashtable keys, the properties of custom classes can be specifically typed.
With scalar values, you can then simply let PowerShell perform the from-string conversion for you - except that Boolean strings need special treatment (see comments in source code below).
With arrays, things are trickier. The solution below uses [System.Management.Automation.PSParser]::Tokenize() to parse the string, but is currently limited to recognizing string and number literals.
Note: It is tempting to use Invoke-Expression on the entire array, but that would be a security risk, because it opens to the door to arbitrary code execution. While there are legitimate uses - such as on a string known to represent a number below - Invoke-Expression should generally be avoided.
(If you don't want to define classes, you can derive the types from the values of hashtable $values and use [System.Management.Automation.LanguagePrimitives]::ConvertTo() to convert the strings to those types, as shown in LotPings' answer, though note that arrays and Booleans still need special treatment as shown below.)
# Define a custom [Values] class
# with specifically typed properties.
class Values {
[bool] $Boolean
[int] $Int
[datetime] $DateTime
[Array] $Array
}
# Instantiate a [Values] instance
$values = [Values] #{
Boolean = $true
Int = 5
DateTime= (Get-Date)
Array = #("A", "B", "C")
}
$stringValues = #{
Boolean = 'false'
Int = '10'
DateTime = '2019-01-02 14:45:59.146'
Array = '#("X", "Y", "Z")'
}
"INITIAL VALUES:"
foreach ($key in $values.psobject.properties.Name) {
($key + " = " + $values.$key + " (" + $values.$key.GetType().FullName + ")")
}
""
"UPDATING..."
foreach ($key in $stringValues.Keys) {
switch ($key) {
'Array' {
# Parse the string representation.
# Assumptions and limitations:
# The array is flat.
# It is sufficient to only support string and numeric constants.
# No true syntax validation is needed.
$values.$key = switch ([System.Management.Automation.PSParser]::Tokenize($stringValues[$key], [ref] $null).Where( { $_.Type -in 'String', 'Number' })) {
{ $_.Type -eq 'String' } { $_.Content; continue }
{ $_.Type -eq 'Number' } { Invoke-Expression $_Content; continue }
}
continue
}
'Boolean' { # Boolean scalar
# Boolean strings need special treatment, because PowerShell considers
# any nonempty string $true
$values.$key = $stringValues[$key] -notin 'false', '$false'
continue
}
default { # Non-Boolean scalar
# Let PowerShell perform automatic from-string conversion
# based on the type of the [Values] class' target property.
$values.$key = $stringValues[$key]
}
}
}
""
"UPDATED VALUES:"
foreach ($key in $values.psobject.properties.Name) {
($key + " = " + $values.$key + " (" + $values.$key.GetType().FullName + ")")
}
This yields:
INITIAL VALUES:
Boolean = True (System.Boolean)
Int = 5 (System.Int32)
DateTime = 04/24/2019 14:45:29 (System.DateTime)
Array = A B C (System.Object[])
UPDATING...
UPDATED VALUES:
Boolean = True (System.Boolean)
Int = 10 (System.Int32)
DateTime = 01/02/2019 14:45:59 (System.DateTime)
Array = X Y Z (System.Object[])
Agreed on the Write-Host thing. It should really only be used to leverage color output and some specific format cases. Output to the screen is the default as you'll see in my response.
You could do the below, but that date string is a bit odd, well, for me, well, I've not seen anyone use that format. So, I modified it for US style, but change as needed for your language.
$values = #{
'Boolean' = $true
'Int' = 5
'DateTime'= (Get-Date)
'Array' = #('A', 'B', 'C')
}
$stringValues = #{
'Boolean' = 'false'
'Int' = '10'
'DateTime'= '2019-01-02 14:45:59'
'Array' = "#('X', 'Y', 'Z')"
}
'INITIAL VALUES:'
foreach ($key in $values.Keys)
{
"$key = $($values[$key]) $($values[$key].GetType())"
}
"`nUPDATING..."
foreach ($key in $stringValues.Keys)
{
switch ($key)
{
Boolean {[Boolean]$values[$key] = $stringValues['$'+$key]}
Int {[Int]$values[$key] = $stringValues[$key]}
DateTime {[DateTime]$values[$key] = $stringValues[$key]}
Array {[Array]$values[$key] = $stringValues[$key]}
default {'The value could not be determined.'}
}
}
"`nUPDATED VALUES:"
foreach ($key in $values.Keys)
{
"$key = $($values[$key]) $($values[$key].GetType())"
}
# Results
INITIAL VALUES:
DateTime = 04/24/2019 01:44:17 datetime
Array = A B C System.Object[]
Boolean = True bool
Int = 5 int
UPDATING...
UPDATED VALUES:
DateTime = 01/02/2019 14:45:59 datetime
Array = #("X", "Y", "Z") System.Object[]
Boolean = False bool
Int = 10 int
Thanks to #LotPings, #mklement0, and #postanote for giving me a few ideas, so here is the solution I will go with:
$values = #{
"Boolean" = $true
"Int" = 5
"DateTime"= (Get-Date)
"Array" = #("A", "B", "C")
}
$stringValues = #{
"Boolean" = 'false'
"Int" = '10'
"DateTime"= '2019-01-31 14:45:59.005'
"Array" = 'X,Y,Z'
}
"INITIAL VALUES:"
foreach ($key in $values.Keys) {
($key + " = " + $values[$key] + " (" + $values[$key].GetType().FullName + ")")
}
"`nUPDATING..."
foreach ($key in $stringValues.Keys) {
$value = $stringValues[$key]
if ($values[$key] -is [Array]) {
$values[$key] = $value -split ','
}
elseif (($values[$key] -is [Boolean]) -or ($values[$key] -is [Switch])) {
$values[$key] = $value -notin 'false', '$false', '0', ''
}
else {
$values[$key] = [System.Management.Automation.LanguagePrimitives]::ConvertTo($value, $values[$key].GetType())
}
}
"`nUPDATED VALUES:"
foreach ($key in $values.Keys) {
($key + " = " + $values[$key] + " (" + $values[$key].GetType().FullName + ")")
}
OUTPUT:
INITIAL VALUES:
DateTime = 04/25/2019 09:32:31 (System.DateTime)
Array = A B C (System.Object[])
Boolean = True (System.Boolean)
Int = 5 (System.Int32)
UPDATING...
UPDATED VALUES:
DateTime = 01/31/2019 14:45:59 (System.DateTime)
Array = X Y Z (System.String[])
Boolean = False (System.Boolean)
Int = 10 (System.Int32)
I adjusted the format of the array in the string value (which, as I mentioned in the question, was an option). The actual code that will use this will be a bit different, but the basic idea is here. The only caveat that I noticed is that the array data type gets changed from object[] to string[]. Ideally, I'd like to keep it as-is, but it would not change the functionality of the code, so it is fine. Thanks again to all for the ideas and corrections, and if you come up with better alternatives, feel free to post.

Tidying up a powershell script

So I need help tidying up a script that I have. The purpose of this script is to make 18 different sql files based on the data below 18 different column headers. What my script does now is make 1 sql file based on which column I choose to input via "Read-Host". This is my current script
function get-header
{Read-Host "Type the Column header betwen B-Z for which sql files needs to be created"
}
function get-column
{
Read-Host "Type the Column number"
}
do
{
$val = get-header
}
while(!($val))
do
{$col = get-column
}
while(!($col))
switch ($val)
{
"B"{$column = "1"}
"C"{$column = "2"}
"D"{$column = "3"}
"E"{$column = "4"}
"F"{$column = "5"}
"G"{$column = "6"}
"H"{$column = "7"}
"I"{$column = "8"}
"J"{$column = "9"}
"K"{$column = "10"}
"L"{$column = "11"}
"M"{$column = "12"}
"N"{$column = "13"}
"O"{$column = "14"}
"P"{$column = "15"}
"Q"{$column = "16"}
"R"{$column = "17"}
"S"{$column = "18"}
"T"{$column = "19"}
"U"{$column = "20"}
"V"{$column = "21"}
"W"{$column = "22"}
"X"{$column = "23"}
"Y"{$column = "24"}
"Z"{$column = "25"}
default { $column = 'Unknown' }
}
if ($column -eq 'Unknown')
{
Write-Warning "Not a valid input"
return
}
$csv = Import-Csv "Indices Updates - September 2018.csv" -Header 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26
$date = (Get-Date -Format "MM/dd/yyyy").Replace("-","/")
$sql = #("INSERT INTO benchmark_values(created_at,benchmark_id,date,amount,created_by_username)
foreach($data in $csv)
{
$secondcolumn = [int]$column + 1
$sql += "('$date',$col,'$($data.1)',$($data.$secondcolumn),'BPylla'),"
}
$sql | Out-File "sqldata.sql"
Now I want to get rid of read-host entirely because I dont want to input any values. I also will give an example of what the csv file looks like and what the sql file should look like.
So the goal is to produce different sql files from each column of information using the the sql format posted. I already have the template for that in my script now, I just need the script to create all the sql files based on headers and still input the data below the headers in the new sql files. Any help would be greatly appreciated! Thanks!

Getting sum in zend

trying to get value1 * value2
$wTrakcie = $pozycja->select('SUM(ilosc * cenaSprzedazy) AS sum')
->from('pozycja',array())
->join('preorder',array())
->where('preorder.sprzedawca_id = ?',$sprzedawca_id)
->where('preorder.preorder_id = pozycja.preorder_id')
->setIntegrityCheck(false);
$wynik = $pozycja->fetchAll($wTrakcie);
return $wynik->sum;
but I got
Notice: Undefined property: Zend_Db_Table_Rowset::$sum in C:\xampp\htdocs\spms\application\models\DbTable\Pozycja.php on line 29
what's the problem?
query is correct!
Your code should look like:
$wTrakcie = $pozycja->select()
->from('pozycja', array('sum' => 'SUM(ilosc * cenaSprzedazy)'))
->join('preorder', array())
->where('preorder.sprzedawca_id = ?', $sprzedawca_id)
->where('preorder.preorder_id = pozycja.preorder_id')
->setIntegrityCheck(false);
$wynik = $pozycja->fetchRow($wTrakcie);
return $wynik->sum;

Uncaught exception 'MongoCursorException' with message .... duplicate key error index:

Here's my code:
When i try to work it, there's an error as it:
"Fatal error: Uncaught exception 'MongoCursorException' with message
'localhost:27017: E11000 duplicate key error index:
futbol_db.maclar.$kod_1_link_1 dup key:
{ : null, : null }' in /var/www/html/cagkansokmen/futbol/db/maclar.php:182
Stack trace: #0 /var/www/html/cagkansokmen/futbol/db/maclar.php(182):
MongoCollection->insert(Array) #1 {main} thrown in
/var/www/html/cagkansokmen/futbol/db/maclar.php on line 182"
The problem is about insert. Because, when i drop insert code, there's no problem about this code. But if i try to insert data, there's an error just as i said.
How can i fix it?
$collection1 = $db->lig_kod;
$collection_maclar = $db->maclar;
$collection1->ensureIndex(array("kod" => 1, "link" => 1), array("unique" => true, "dropDups" => true));
$a = $collection1->find(array())->limit(15)->skip(0);
foreach($a as $b){
$kod = $b["kod"];
$link = $b["link"];
$parc = explode(',', $link);
$ligkoduson = $parc[0].",".$parc[1];
$url2 = "http://www.stats.betradar.com/s4/gismo.php?&html=1&id=1424&language=tr&clientid=35&state=".$ligkoduson.",5_".$kod.",9_fixtures,231_fixtures,23_1,242_21&child=0";
$url2 = curl($url2);
$url2 = str_replace("\t","",$url2);
$url2 = str_replace("\n","",$url2);
$url2 = str_replace("\r","",$url2);
$bul = ara("<![CDATA[", "]]>", $url2);
$sonuc = ara("setState('", ",", $bul[0]);
$say = count($sonuc);
for($i = 0; $i<$say; $i++){
$sezonbul = $sonuc[$i];
$lonk = "http://www.stats.betradar.com/s4/gismo.php?&html=1&id=2127&language=tr&clientid=35&state=".$ligkoduson.",".$sezonbul.",9_fixtures,231_full,23_1&child=2";
$fiksturlink = curl("http://www.stats.betradar.com/s4/gismo.php?&html=1&id=2127&language=tr&clientid=35&state=".$ligkoduson.",".$sezonbul.",9_fixtures,231_full,23_1&child=2");
$fiksturlink = str_replace("\t","",$fiksturlink);
$fiksturlink = str_replace("\n","",$fiksturlink);
$fiksturlink = str_replace("\r","",$fiksturlink);
$kategori = ara('title="', '"', $fiksturlink);
$kategori_parcala = explode(' > ', $kategori[0]);
$tur = trim($kategori_parcala[0]);
$ulke = trim($kategori_parcala[1]);
$lig = $kategori_parcala[2];
$lig_parcala = explode(' ', $lig);
$lig_bosluk = count($lig_parcala)-1;
$sezon = trim($lig_parcala[$lig_bosluk]);
$lig_son = trim(str_replace($sezon, "", $lig));
$takimlar = ara('<span class="teams">', '</a>', $fiksturlink);
$timebul = ara('<td class="datetime">', '</td>', $fiksturlink);
$fhbul = ara('<td class="p1 ">', '</td>', $fiksturlink);
$ftbul = ara('<td class="nt ftx ">', '</td>', $fiksturlink);
$dongusay = count($takimlar);
echo $dongusay."<br>";
for($dongu = 0; $dongu<$dongusay; $dongu++){
$takimlarbul = ara('">', '</span>', $takimlar[$dongu]);
$home = trim($takimlarbul[0]);
$away = trim($takimlarbul[2]);
$time = trim($timebul[$dongu]);
$time_ayir = explode(' ', $time);
$yil_ayir = explode('/', $time_ayir[0]);
$gun = $yil_ayir[0];
$ay = $yil_ayir[1];
$yil = $yil_ayir[2];
$saat_ayir = explode(':', $time_ayir[1]);
$saat = $saat_ayir[0];
$dk = $saat_ayir[1];
$time_sonuc = mktime($saat, $dk, 0, $ay, $gun, $yil);
$fh = trim($fhbul[$dongu]);
if(empty($fh)){
$fh1 = null;
$fh2 = null;
}else{
$fh_ayir = explode(':', $fh);
$fh1 = $fh_ayir[0];
$fh2 = $fh_ayir[1];
}
$ft = trim($ftbul[$dongu]);
if(empty($ft)){
$ft1 = null;
$ft2 = null;
}else{
if(strpos($ft, '(')){
$parcala1 = explode('(', $ft);
$ft_ayir = explode(':', $parcala1[0]);
$ft1 = $ft_ayir[0];
$ft2 = $ft_ayir[1];
}else{
$ft_ayir = explode(':', $ft);
$ft1 = $ft_ayir[0];
$ft2 = $ft_ayir[1];
}
}
echo $ligkoduson."-".$sezonbul."-".$tur."-".$ulke."-".$lig_son."-".$sezon."-".$home."-".$away."-".$time_sonuc."-".$fh1."-".$fh2."-".$ft1."-".$ft2."<br>";
$collection_maclar->insert(array(
'ulke_kodu'=>$ligkoduson,
'sezon_kodu'=>$sezonbul,
'tur'=>$tur,
'ulke'=>$ulke,
'lig'=>$lig_son,
'sezon'=>$sezon,
'home'=>$home,
'away'=>$away,
'tarih'=>$time_sonuc,
'fh1'=>$fh1,
'fh2'=>$fh2,
'ft1'=>$ft1,
'ft2'=>$ft2
));
}
}
}
You have an unique index on "kod" and "link", but the document you are inserting doesn't include either of these fieldnames.
That means the first document you insert will have these values as null, and the second one will too.. but fails as it violoates the unique index you created.
Note that the "dropDupe" flag you provide with the ensureIndex() command only means "drop existing duplicates", not "if I try to use that key again, drop the previous document".
Your current code seems to be ensuring this index on the "lig_kod" collection, but I suspect you may have previously (maybe accidentally) used the $collection_maclar variable, rather then the $collection1 variable and executed the code, resulting in creating the index on the maclar collection.
-Hannes

Array in Powershell

I used to work with array in VBSCRIPT like below… I am not sure how I should do it in PowerShell… Can any help me out…?
CODE --> VBSCRIPT
dim arrErrors(12)
arrErrors(0) = "APP0"
arrErrors(1) = " APP1"
arrErrors(2) = " APP2"
arrErrors(3) = " APP3”
arrErrors(4) = "APP4"
arrErrors(5) = "APP5"
arrErrors(6) = "APP6"
arrErrors(7) = "APP7"
arrErrors(8) = "APP8"
arrErrors(9) = "APP9"
arrErrors(10) = "APP10"
arrErrors(11) = "APP11"
arrErrors(12) = "APP12"
for i = 0 to ubound(arrErrors)
strError = arrErrors(i)
if (left(lcase(strErrorLine), len(strError)) = lcase(strError)) then
objErrorLog.WriteLine strErrorLine & vbTab & strComputer & vbTab & "Found Error number" & vbTab & i
exit for
end If
Create a hash table. Populate it with error names and values. Parse the error string and look if the hash table contains it. Like so,
$htErr = #{ "app0" = 0; "app1" = 1; "app2" = 2 } # Populate hash table
$error = ... # get the error string from somewhere.
if($htErr[$error]) {
"Found error, code " + $htErr[$error] # Get code based on error string
}