The issue occurs because your string includes double quotes, which you need to escape, either by entering them twice like this:
$MyQuery = "select a.asset_name as 'ASSET_NAME',b.asset_name AS 'ASSET', from positions a join appraisal b on b.asset_name LIKE CONCAT(""%"",a.asset_name,""%"") where a.unrealised!= 0 ;"
Or by putting a backtick character before them:
$MyQuery = "select a.asset_name as 'ASSET_NAME',b.asset_name AS 'ASSET', from positions a join appraisal b on b.asset_name LIKE CONCAT(`"%`",a.asset_name,`"%`") where a.unrealised!= 0 ;"
Alternatively you can use a here-string, which works by surrounding the string with @'
and '@
(or @"
and "@
) and makes everything between these characters interpreted as part of the string block, regardless of what other characters you include:
$MyQuery = @'
select a.asset_name as 'ASSET_NAME',b.asset_name AS
'ASSET',
from positions a
join appraisal b
on b.asset_name LIKE CONCAT("%",a.asset_name,"%") where
a.unrealised!= 0 ;
'@
Note that with a here-string you can’t put anything on the same line after the opening @'
and the closing '@
must be on a line on it’s own, and can’t have any whitespace before it.
If you use the double quoted version of the here string, you can still embed variables in the string and have them expanded.
For more information on here-strings see here.
When you want to convert a string to a secure string with ConvertTo-SecureString, you may get the
following error message
Reason
This happens when you try to convert a regular string to a secure string.
“Convert To Secure String” string only means “to protect in memory”.
However, the standard input for the ConvertTo-SecureString cmdlet is an encrypted string.
Workaround
As a workaround you can use the AsPlainText parameter, which has to be associated with the Force
parameter (to confirm you understand the implications).
$MySecureString = ConvertTo-SecureString -String $MyPlainTextString -AsPlainText -Force
Получаю по API JSON результат. Но русские буквы отображаются в виде знаков вопроса.
Есть идеи, товарищи? Спасибо заранее
Что запускаю:
$url2 = "http://********/rooms?limit=3&access_token=******"
$rres = Invoke-WebRequest -Method GET -Uri $url2 -ContentType "application/json;charset=utf-8" | ConvertFrom-Json
$Lmres = $rres.chunk
Write-Host $Lmres[0].Content
Получаю:
@{body=???? ??????) ; msgtype=m.text}
@{body=??????????????; msgtype=m.text}
@{body=??????????; msgtype=m.text}
Кодировку запроса к json менял на win-1251, ничего не изменилось.
Viktor Tomilov
8,3054 золотых знака25 серебряных знаков63 бронзовых знака
задан 28 фев 2018 в 6:36
В данной строке:
$rres = Invoke-WebRequest -Method GET -Uri $url2 -ContentType "application/json;charset=utf-8"
вы задаёте не кодировку отклика, а кодировку запроса. Нужно менять кодировку уже возвращаемых данных. Не могу сэмулировать именно ваш запрос, поскольку адрес неизвестен, но выглядеть это должно как-то так:
$rus_result = [System.Text.Encoding]::GetEncoding('windows-1251').GetString([Byte[]]$your_result)
или то же самое, но с utf-8 вместо windows-1251
ответ дан 28 фев 2018 в 6:58
Viktor TomilovViktor Tomilov
8,3054 золотых знака25 серебряных знаков63 бронзовых знака
2
Массивы в Powershell являются аналогами списков в Python. Легче всего воспринимать эти понятия как хранение в одной переменной множества значений. То есть это структура данных, которую можно перебирать и вызывать отдельный элемент используя индексы. Массивы, они же и множества и array, в Powershell и других языках программирования являются отдельным типом данных так же как числа и строки.
Создание
Массивы являются базовой возможностью Powershell, и их создание делается просто. Для создания нужно использовать символы @() :
$array = @()
$array.count
Count (в переводе счетчик) — показывает сколько у нас элементов в массиве. Так как мы создали пустое множество он равен нулю.
Можно создать сразу со значениями. Что бы это выполнить нужно добавить значения, разделенные запятой, внутри @() :
$lst = @('Первый', 'Второй', 'Четвертый', 'Третий')
$lst.Count
$lst
Написав $array мы вывели значения переменной. Каждое из четырех значений выводится с новой строчки.
Другой способ создания — это писать значения с новой строчки. В этом случае запятые ставить не обязательно:
$lst = @('Первый'
'2'
'Третий'
4)
$lst.Count
$lst
Хоть такая возможность и есть в Powershell, я бы не советовал использовать без запятых. В остальном, с использованием табуляции, такой синтаксис может улучшить читаемость (особенно если у нас сотни значений).
Еще один способ объявления — это не указывать скобки и знак @ :
$lst = '7',8,'Один','One'
Следующий вариант не используется на практике, но вы можете иметь его ввиду:
$lst = Write-Output Один 2 Трии '4'
Обратите внимание, что число 4 стало строкой только тогда, когда ее поместили в кавычки.
Получение элементов
Как уже было показано выше получить весь массив можно написав переменную, но так же можно использовать другие методы как смещение и индексы.
Индексы
Когда нужно получить конкретный элемент мы указываем скобки []. Самое первое значение массива имеет идентификатор 0. На следующем примере мы получим первый объект:
$arraylist = 'Первый','Второй','Третий'
$arraylist[0]
Для получения следующих индексов просто измените число:
$arraylist[2]
На примерах выше мы получили данные по их индексам. В отличие от большинства языков в Powershell мы можем указывать несколько индексов, которые хотим получить. Так же можно вызвать один и тот же элемент неограниченное количество раз:
$arraylist[0,2]
Срез (slice) или последовательность — это когда мы получаем данные с одного индекса по другой. Последовательности обозначаются двумя точками ‘..’ . Для примера получим первые три значения:
$arraylist = @('admin@login', 'admin', 'Password', '20.02.2004', '????', '????')
$arraylist[0..2]
$arraylist[1..100]
Как видно мы можем получить данные не в строгой последовательности относительно массива. Так же указав несуществующий индекс ‘100’ мы не получили ошибку, а вывели все значения с первого до последнего. Если вызвать единственный элемент, который не будет существовать, то значения будут равны Null.
$null -eq $arraylist[200]
В большинстве языков отрицательное число ‘-1’ обозначает последний объект массива. Обратите внимание, что использование [-1..0] и [0..-1] приведет только к получению первого и последнего элемента:
$arraylist[0..-1]
$arraylist[-1..0]
Можно указать -2 для получения предпоследнего объекта и т.д. Последний объект можно получить и таким образом:
$arraylist.GetUpperBound(0)
Если вы попытаетесь получить индекс у несуществующего массива, или с несуществующими значениями, то это может привести к разным последствиям:
$arraylist = $null,$null
$arraylist[0]
$arraylist = $null
$arraylist[0]
Возможные ошибки:
- Не удается индексировать в массив NULL.
- Cannot index into a null array.
Если вы не совсем понимаете как работает NULL в Powershell, то советовал бы вам прочитать предыдущую статью.
Использование счетчика Count
Счетчик удобно использовать, когда мы хотим проверить количество элементов в массиве:
$lst = '0','2','3','4'
$lst.count
if ($lst.count -eq 4){Write-Output 'Hacked!'}
Используя счетчик можно получить и элемент массива. Если вы никогда не работали с индексами обращайте внимание, что счетчик возвращает количество элементов в массиве, но индексация начинается с 0 элемента. То есть для получения последнего элемента нам нужно вычесть 1:
$lst[$lst.count - 1]
$lst[0..($lst.count - 1)]
$lst[2,($lst.count - 1)]
Если вы не закроете в скобки выражение в случае получения среза, то будут следующие ошибки:
- Сбой вызова метода из-за отсутствия в [System.Object[]] метода с именем «op_Subtraction».
- Method invocation failed because [System.Object[]] does not contain a method named ‘op_Subtraction’.
Замена элементов
Для замены элементов так же нужно указать индекс. Если мы хотим заменить первый объект, то соответственно нужно указать индекс 0:
$data = @(7,5,8,4,5)
$data[0]=0
$data
$data[-1]='Пять'
$data
Указание несуществующего индекса вызовет ошибки:
- Index was outside the bounds of the array
- Индекс находился вне границ массива.
Итерации
Кроме индексов с массивом часто приходится работать используя циклы и другие методы перечисления. Далее будет рассказано об этом.
Конвейер или Pipeline
В примере ниже мы проверим доступность хостов передав каждый объект массива через конвейер:
$sites = 'localhost','fixmypc.ru'
$sites | ForEach-Object {ping $_}
Цикл ForEach
В циклах массивы используются похоже:
foreach ($site in $sites)
{
ping $site
}
Так же доступен метод foreach, который немного отличается синтаксисом, но работает так же:
$sites.foreach({ping $_})
Использование switch
Switch это аналог условий, который объединен в единую конструкцию. Мы можем объявить switch и передать в наш список:
$data = 'folder','hack'
switch( $data )
{
'folder' {'Создать папку с именем'; New-Item -Path 'C:\Array' -ItemType Directory}
'file' {'Создать файл'}
'hack' {'Взломать аську'; ping fixmypc.ru}
Default {'Ничего не создавать'}
}
Обновление значений через циклы
Если нам понадобится обновить весь массив мы обратимся к циклам и мы можем столкнуться с трудностями. Проблемы заключаются в том, что в цикле находится не сам массив, а его значения и мы не сможем их изменить так. Обойти эту ситуацию можно двумя путями.
Первый способ — это обратиться к каждому значению по индексу, а саму ‘длину’ индексов измерить методами, которые описаны выше:
$val = @(1,2,3)
0..($val.Count-1) | foreach {$val[$_]=$val[$_] + 1}
В Powershell мы можем генерировать список из чисел указав только первое и последнее число и именно это я делал в следующей строке:
0..($val.Count-1)
В другой строке я указал заменить число под этим индексом на новое прибавив 1:
$val[$_]=$val[$_] + 1
Еще один способ через ‘for’, который практически не применяется PS:
for ( $index = 0; $index -lt $array.count; $index++ )
{
$array[$index] = ($array[$index] + 1) -f $array[$index]
}
Использование объектов в массиве
В предыдущих примерах мы рассматривали работу с типами данных, но массивы могут хранить любые данные и объекты. Такие методы удобно использовать, когда собираете много данных и часто с ними работаете:
$data = @(
[pscustomobject]@{Computer='localhost';Login='admin';Process=Get-Process -ComputerName 'localhost'},
[pscustomobject]@{Computer='127.0.0.1';Login='lizun';Process=Get-Process -ComputerName '127.0.0.1'}
)
$data
Вызвав переменную вы увидите, что представление данных почти не отличается от вывода командлетов.
Для получения данных мы можем указывать индексы:
$data[0]
После получения объекта вызвать свойство (‘колонку’ с примера выше), которое нам нужно:
$data[0].Computer
$data[0].Process
Когда нужно будет получить, например, все имена компьютеров используем циклы:
$data | ForEach-Object {$_.Computer}
Можно вызвать напрямую или командлет Select-Object:
$data | select Computer
$data.Computer
Фильтрация массивов через Where-Object
Фильтрация можно использовать, например, когда нам нужно найти все цифры из массива наполненным разными данными. На следующем варианте видно, что она мало чем отличается от того, что мы применяем в командлетах:
$list = @(
[pscustomobject]@{Name='Dima';SubName='Penkin'},
[pscustomobject]@{Name='Valera';SubName='Lerov'}
)
$list | where {$_.Name -like 'D*' -and $_.SubName -like '*n'}
$list | Where-Object SubName -eq 'Lerov'
Аналогично способу выше есть метод, который фильтрует так же:
$list.Where({$_.Name -eq 'Dima'})
Обновление объектов через цикл
При использовании циклов таким способом мы будем обновлять значение Name во всех значениях массива:
foreach($iden in $list)
{
$iden.Name = 'Sasha'
}
Если вы хотите заменить конкретное свойство, нужно использовать условия:
$list = @(
[pscustomobject]@{Name='Dima';SubName='Penkin'},
[pscustomobject]@{Name='Valera';SubName='Lerov'}
)
foreach($iden in $list){
if ($iden.Name -eq 'Dima'){$iden.Name='dd'}
}
$list
Заменить весь объект используя цикл нельзя.
Операторы
-join
Join это оператор, который может преобразовать весь массив в единую строку где разделителем может быть любой символ:
$string_array = @('Masha', 'Sasha', 'Dima')
$string_array -join '.'
$string_array -join ' пошел к '
Следующие варианты просто сольют все символы в одну строку без пробелов:
$string_array = @('Masha', 'Sasha', 'Dima')
$string_array -join $null
-join $string_array
Можно использовать для логирования ошибок:
$data = @((Get-Date).Day, 'Error 5051', (hostname))
"Ошибка $data"
-replace
Операторы замены проверит каждый элемент и выполнят замену совпадающих значений:
$massive = 'Lena','Misha','Pika'
$massive -replace 'M','S'
$massive.Replace('L','p')
Более подробно мы уже говорили о replace с Powershell.
-split
Split преобразует строку в список. В качестве разделителя я указал пробел:
$massive = 'Преобразование строки'
$massive -split ' '
$massive.Split(' ')
-contains
Этот оператор проверяет точное вхождение и возвращает булево значение True или False:
$list = 'Вася','Федя'
# Верно
$list -contains 'Вася'
# Не верно
'Вася' -contains $list
-in
Отличия от contains в том, что он появился в Powershell 3 и создан для более удобной читаемости. В операторах Powershell важно соблюдать позиции того что мы ищем и где. Ошибки могут быть очень неявными. В случае с contains объект должен находиться слева, а в in справа:
$list = 'Вася','Федя'
# Верно
'Вася' -in $list
# Не верно
$list -in 'Вася'
Этот оператор так же можно использовать для поиска в массиве Powershell.
-eq и -ne
При использовании сравнения ‘eq’ у нас вернется либо само значение, либо False. В случае неравенства ‘ne’ вернутся либо остальные значения, либо True. Важно использовать искомое значение справа, а объект слева:
$data = @('один','два','три')
# Верно
$data -eq 'один'
$data -ne 'один'
# Не верно
'один' -eq $data
'один' -ne $data
Если нужно проверить, что все значения в листах совпадают требованиям, можно воспользоваться такой конструкцией:
$array = @('Ok','Ok','not Ok')
if ( -not ( $array -ne 'Ok') ){'Что-то не так, это False'}
$array = @('Ok','Ok','Ok')
if ( -not ( $array -ne 'Ok') ){'Все ок'}
-match и -like
Оператор match позволяет использовать регулярные выражения. Он будет искать каждое совпадение в массиве и вернет их:
$var = @('QQ-11-22','22-44-SS','FF-GG-HH')
# Верно
$var -match '22'
# Не верно
'22' -match $var
В операторе like можно использовать знак *, который будет идентифицировать пропущенный текст. Следующий пример сработает с ошибкой в случае с match:
$var = @('QQ-11-22','22-44-SS','FF-GG-HH')
# Верно
$var -like '2*S'
# Не верно
'2*S' -like $var
Похоже сработает Select-String:
$var = @('QQ-11-22','22-44-SS','FF-GG-HH')
$var | Select-String 22
Проверка $null
Если мы будем проверять существующий массив, в котором нет значений, то следующий пример вернет False:
$foo = @()
if($foo -eq $null) { "Пустой" } else { "Значения есть" }
Он так же вернет False, если внутри будет $null:
$foo = @($null)
if($foo -eq $null) { "Пустой" } else { "Значения есть" }
Что бы избежать ошибок нужно добавлять счетчик:
if ( $foo -ne $null -and @($foo).count -gt 0 ){'Все по маслу'}
Сортировка массива
Для сортировки в Powershell используется командлет Sort-Object:
$sort = 4,7,3,2,4
$sort | Sort-Object
$sort = 'V','F','A'
$new_sort = $sort = 'V','F','A' | Sort-Object
Более подробно командлет Powershell Sort-Object уже рассматривался.
Добавление элементов в массив Powershell
Фактически Powershell не позволяет добавлять элементы в массив. Для того что бы это сделать массив сначала удаляется, а затем создается новый. Возможно кому-то будет более понятно это под «неизменяемый объект». Тем не менее процесс удаления и создания сильно упрощен в PS и вам не составит труда это сделать.
Сложение
Для создания нового массива можно указать оператор сложения для двух существующих:
$a = @('1')
$b = @('2','4')
$c = $a + $b
$c
Другой способ существует во множестве языках:
$array_add = @('1')
$array_add += 2
$array_add
Создание из конвейера
Можно генерировать новый массив используя старый:
$array_add = @(0)
1..5 | ForEach-Object { $array_add+=$_ }
$array_add
Типы массивов
По умолчанию массив в Powershell создается типа [PSObject[]]. Это позволяет хранить любые типы данных. Если вы хотите хранить строгие типы данных, например только числа или определенный набор, то вы можете использовать следующие методы:
Массив из определенных типов данных
Используя следующий методы можно создать любой массив со строгими типами данных. Пример ниже позволяет использовать только числа:
[int[]] $num = 9,2,3,'4'
Обратите внимание, что 4 объявлена строковой, но она сама преобразуется в число без ошибок. В случае добавления букв будет ошибка:
- Не удается преобразовать значение «s» в тип «System.Int32». Ошибка: «Входная строка имела неверный формат.»
- Cannot convert value «s» to type «System.Int32». Error: «Input string was not in a correct format.»
Так же можно сделать и со строками, но в таком случае все добавленные данные преобразуются в строки:
[string[]] $str = '8','s','d'
$str+= 1
Универсальные списки
Универсальные списки относятся к C#, в котором нужно определять типы данных. Так мы создадим список из строк:
$list = [System.Collections.Generic.List[string]]::new()
А так будет создан список из целых чисел:
$list = [System.Collections.Generic.List[int]]@(32,55,66)
Начиная с версии Powershell 5 можно сократить синтаксис используя using namespace. Using указывается в самом начале скрипта.
using namespace System.Collections.Generic
$list = [List[int]]@(31,32,33)
Следующий синтаксис добавит число в список:
$list.Add(10)
Значения так же можно получать по индексам:
$list[-1]
Для удаления используется следующий синтаксис:
using namespace System.Collections.Generic
$var = [List[string]]@('Один','Два','Три')
[void]$var.Remove('Один')
Можно так же удалять по индексам:
$delete = $var[1]
$var.remove($delete)
List[PSObject]
Список из любого типа данных можно создать и так:
using namespace System.Collections.Generic
$list = [List[PSObject]]::new()
ArrayList
Для поддержки удаления, которого нет в обычных массивах, можно использовать ArrayList. Они так же быстрее работают. Для создания такого массива используйте следующий синтаксис:
$arraylist = [System.Collections.ArrayList]::new()
[void]$arraylist.Add('Someval')
$arraylist
Для удаления:
$arraylist.Remove('Someval')
Другие методы по работе с массивами
Кроме основных методов по работе с массивами есть методы, которые позволяют генерировать списки и создавать фиксированного размера. Далее разберем на примерах.
Фиксированный размер
В Powershell можно создать список с предопределенным размером:
$data = [Object[]]::new(5)
$data.count
Умножение
Так же как и в других языках массивы можно умножать:
$var = @('A','B','C')
$var*5
Похожий метод, который создаст 10 нулей:
[int[]]::new(10)
Вложенность
Массив внутри других массивов называются вложенными. Работа с ними отличается только индексами:
$array = @(
@(2,2,2),
@(3,3,3)
)
Чтобы получить значение нужно использовать индексы дважды:
$array[0][1]
$array[1][1]
Учитывая это можно создать двумерный массив.
Двумерные массивы и многомерные
Учитывая предыдущие примеры мы сможем создать двумерный массив или матрицу:
$dv_massive = @(
@(1,2,3,4),
@(3,4,5,6),
@(7,8,9,10)
)
Для получения, например, единицы нам нужно использовать индексы дважды:
$dv_massive[0][0]
Если вызвать весь массив, то он будет выведен построчно. Можно вывести и так:
ForEach($el in $dv_massive){Write-Host $el[0] $el[1] $el[2] $el[3]}
Можно вывести указав SyncRoot:
$dv_massive | select SyncRoot
Многомерный массив можно создать и вывести с параметрами так:
$ma_massive = New-Object 'object[,]' 5,3
# Внесение в первую колонку
$ma_massive[0,0] = 1
$ma_massive[1,0] = 2
$ma_massive[2,0] = 3
$ma_massive[3,0] = 4
$ma_massive[4,0] = 5
# Во вторую
$ma_massive[0,1] = 'A'
$ma_massive[1,1] = 'B'
$ma_massive[2,1] = 'C'
$ma_massive[3,1] = 'D'
$ma_massive[4,1] = 'E'
# Третью
$ma_massive[0,2] = 1988
$ma_massive[1,2] = 1999
$ma_massive[2,2] = 1876
$ma_massive[3,2] = 1478
$ma_massive[4,2] = 1247
# Вывод
Write-Host $ma_massive[0,0] $ma_massive[0,1] $ma_massive[0,2]
Write-Host $ma_massive[1,0] $ma_massive[1,1] $ma_massive[1,2]
Write-Host $ma_massive[2,0] $ma_massive[2,1] $ma_massive[2,2]
Write-Host $ma_massive[3,0] $ma_massive[3,1] $ma_massive[3,2]
Write-Host $ma_massive[4,0] $ma_massive[4,1] $ma_massive[4,2]
…
Теги:
#powershell