Перейти из форума на сайт.

НовостиФайловые архивы
ПоискАктивные темыТоп лист
ПравилаКто в on-line?
Вход Забыли пароль? Первый раз на этом сайте? Регистрация
Компьютерный форум Ru.Board » Компьютеры » Прикладное программирование » Windows PowerShell 1.x/2.x/CTP

Модерирует : ShIvADeSt

 Версия для печати • ПодписатьсяДобавить в закладки
Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Открыть новую тему     Написать ответ в эту тему

tcg2



Newbie
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Microsoft Windows PowerShell

 
Обсуждаемые темы

    * Работа с SQL
    * Работа с Visual Studio
    * etc.

 
Помощь по использованию консоли pwsh, а также встроенной в Windows консоли powershell.exe  

Всего записей: 7 | Зарегистр. 20-11-2006 | Отправлено: 19:06 29-11-2006 | Исправлено: YuS 2, 18:04 02-06-2020
serik1986



Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Товарищи, не силен я в написании скриптов в PowerShell.
Поэтому прошу помочь написать скрипт для вот какой цели:
Нужно чтобы скрипт автоматически создавал на файл сервере папки для секьюрити групп начинающихся с определенной маской (например OfficeGroup_Acc, OfficeGroup_Fin, OfficeGroup_HR...), т.е. в случае если папки с таким же именем нет, то создать.  
А также в этом же цикле исправить/создать права согласно самой секьюрити группы, т.е. если эта папка на основании секьюрити группы например OfficeGroup_Fin, то соответственно владелец и полные права тоже эта группа, ну и естественно перед созданием этих прав сначала подтереть все существующие и уже добавить названные.
 
Также нужен вытекающий из этого еще один скрипт:
Пользователи которые состоят в тех или иных группах должны у себя на рабочем столе обнаружить ярлыки на сетевую папку к которой у них есть доступ, например Вася Пупкин состоит в группах OfficeGroup_HR и OfficeGroup_Law, соответственно у него на рабочем столе будут ярлыки на общие папки OfficeGroup_HR и OffceGroup_Law....
 
Очен надеюсь на помощь или хотя бы на необходимые команды, а я сам их уже постараюсь собрать в общий скрипт. Заранее все спасибо.

Всего записей: 267 | Зарегистр. 29-06-2009 | Отправлено: 21:08 05-03-2018
LevT



Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Что является исходными данными - массив имен групп?  
или же правила добычи этого массива из окружающего мира?  
Во втором случае потрудитесь их изложить!

Всего записей: 17163 | Зарегистр. 14-10-2001 | Отправлено: 22:03 05-03-2018 | Исправлено: LevT, 22:51 05-03-2018
LevT



Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
serik1986
 
попробуйте подтвердить правильность требуемого алгоритма - или уточнить, если я что-то недопонял
первые три функции - рыба, которую ещё предстоит написать в случае, если на самом верхнем уровне скрипт делает именно то, что вам нужно
и можете попробовать сами внести посильную лепту, начав с Get-Group: она вам понадобится в любом случае
 

Код:
 
 
function Get-Group{..}
function Get-MemberDesktop {...}
function Update-Shortcut {param([string]$Group)...}
 
function  Update-MemberDesktop {
[CmdletBinding()]
param(
    [Parameter(ValueFromPipeline)]
    [string[]]$Members,  
    [string]$Group
)
    PROCESS {
        $psitem |  
             Get-MemberDesktop |  
                    Update-Shortcut
-Group $Group
    }
}
 
 
Get-Group -PipelineVariable Group |  
        Get-Member |
                   Update-MemberDesktop
-Group $Group
 

 

Всего записей: 17163 | Зарегистр. 14-10-2001 | Отправлено: 00:40 06-03-2018 | Исправлено: LevT, 17:49 06-03-2018
LevT



Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Я забыл ещё одну ненаписанную функцию - но с нею и так всё ясно
Get-Group | Update-Share
 
 
Добавлено:
 
Где будет выполняться скрипт?
Удобнее всего на файловом сервере с установленным RSAT (AD Management Powershell Cmdlets)
 
Хотя бы для начала.  
Потом уже отлаженный скрипт можно будет при необходимости переделать для remoting.
 
serik1986
Подтвердите, что это годится.

Всего записей: 17163 | Зарегистр. 14-10-2001 | Отправлено: 14:14 06-03-2018
serik1986



Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
LevT

Цитата:
Что является исходными данными - массив имен групп?  
или же правила добычи этого массива из окружающего мира?  
Во втором случае потрудитесь их изложить!  

 
скорее немного первое и от части второе.
Исходные данные берутся из домена, например company.com
в этом домене есть секьюрити группы созданные для управления отделами компании.
Соответственно отдел бухгалтерии = OfficeGroup_Acc
отдел финансов = OfficeGroup_Fin
отдел кадров = OfficeGroup_HR
и т.п.
 
т.е. маской для фильтра множества групп в директории будет "OfficeGroup%"
собрав группы, нужен циклический обход каждой и при остановке на каждой группе проверка существования общей папки с таким же названием, нету - создаем, присваиваем права, если есть - апдейтим права.
 
а т.к. юзеры работать могут на любой машине, то получается нужен доп.скрипт при логоне, который проверит участвует ли залогинившейся юзер в группах по маске "OfficeGroup%" и если их несколько то создаст shortcut на каждую папку.
Думаю скрипт усложнится если как то еще проверять старые shortcut, если предположим права убрали юзеру а ярлык ранее был создан, но это ручками можно чистить так что не хочу усложнять задачу...
 
p.s. да скрипт будет выполнятся на файловом сервер.

Всего записей: 267 | Зарегистр. 29-06-2009 | Отправлено: 14:37 06-03-2018 | Исправлено: serik1986, 14:42 06-03-2018
LevT



Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
AD Cmdlets на файловом сервере стоят уже?
Если нет, то они добавляются визардом среди серверных фич (после ролей)
 

Цитата:
собрав группы, нужен циклический обход каждой и при остановке на каждой группе проверка существования общей папки с таким же названием, нету - создаем, присваиваем права, если есть - апдейтим права.  

 
Значит так. Призываю вас всё-таки прочесть мною написанное и вступить в коммуникацию по этому поводу!
На простые вопросы я ответ получил.
Более сложный вопрос остался без ответа: годится ли вам предложенный мною алгоритм решения вашей задачи именно на Powershell? Суть его выделена жирным.
 
Если же вы продолжите указывать мне алгоритм, которым я должен вам помогать - то лично я пас. Думаю, здесь найдутся помогатели (именно что мне назло), но вообще-то такое поведение со стороны просящего о помощи и невежливо, и непродуктивно.  

Всего записей: 17163 | Зарегистр. 14-10-2001 | Отправлено: 17:28 06-03-2018 | Исправлено: LevT, 20:09 06-03-2018
serik1986



Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
LevT
извините если я Вас чем то обидел или повел не вежливо, я просто некорректно понял Ваш вопрос.
Повторюсь как и в начале диалога, я не силен в PowerShell, и данный алгоритм если чисто интуитивно по процедуре читать должен сработать, я просто синтаксис не понимаю и/или не понимаю как он используется...  к примеру  

Код:
PROCESS {
        $psitem |  
             Get-MemberDesktop |  
                    Update-Shortcut -Group $Group
    }  

этот процесс - это и будет работать как циклический перебор?
 
тут вот накидал получение списка всех групп по фильтру  
 

Код:
Import-Module ActiveDirectory
Get-ADGroup -LDAPFilter "(&(objectCategory=group)(cn=Officegroup_*)(groupType:1.2.840.113556.1.4.803:=2147483648)
)"| format-table name

 
Так верно будет?

Всего записей: 267 | Зарегистр. 29-06-2009 | Отправлено: 13:50 07-03-2018 | Исправлено: serik1986, 13:51 07-03-2018
LevT



Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
serik1986

Цитата:
этот процесс - это и будет работать как циклический перебор?  

 
Да, блок PROCESS внутри функции выполняется над каждым входным элементом, сколько бы их не было. Потому в большинстве случаев можно распрощаться с ручным созданием цикла: внутри движка PS "оно само" всё перемалывает.
 
А где знак |   - там везде подразумевается любое количество объектов, выплюнутое предудущим выражением или функцией и поданное следующей.
Помимо прочих своих достоинств, движок не буферизует здесь данные, а обрабатывает дальше по мере их генерации.
 
 

Цитата:
тут вот накидал получение списка всех групп по фильтру  

 
Только для повторно используемой функции (результат которой подлежит дальнейшей машинной обработке) вы перестарались:
никаких форматов в конце не нужно и прямо вредно!
 
Имя группы получить можно cказав  | Select -ExpandProperty Name
 
Но кмк лучше передавать по "трубе"  следующему командлету сами богатые объекты (AD группы): остальные их свойства могут ещё пригодиться.
 
 
 
Добавлено:
 
ЗЫ. AD у меня будет под рукой завтра, а сегодня я в разъездах.

Всего записей: 17163 | Зарегистр. 14-10-2001 | Отправлено: 14:12 07-03-2018 | Исправлено: LevT, 14:14 07-03-2018
LevT



Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
serik1986
 
слегка изменил вашу функцию:
 

Код:
function Get-Group {
[CmdletBinding()]
[OutputType([Microsoft.ActiveDirectory.Management.ADGroup])]
Param (
    $GroupNameFilter = "OfficeGroup*"
)
END {
             
        Get-ADGroup -Filter 'GroupCategory -eq "Security" -and Name -like $GroupNameFilter'
    }
}

(у powershell-фильтров более человеческий синтаксис, потому там где это возможно следует использовать их)
 
теперь за Вами ваша реализация функции
 

Код:
function Get-UserDesktop {
[CmdletBinding()]
[OutputType([System.IO.DirectoryInfo])]
Param (
    [Microsoft.ActiveDirectory.Management.ADUser[]]$User
)
PROCESS {
             
        $profile = $_.ProfilePath | Get-Item    #не знаю как у вас, а в нашей АД в этом месте бардак, и данных AD может быть вовсе даже недостаточно
 
        $desktop = $profile | Join-Path -ChildPath 'Desktop'
        $desktop | Get-Item  
 
    }
}

 
 
 
Использоваться она будет так:
 

Код:
 
Get-Group |  
    Get-ADGroupMember -Recursive |  
        Get-ADUser |
            Get-UserDesktop
 

 
Содержательно ваша функция мне дальше не нужна, если вы в состоянии написать её согласно спецификации.
На выходе может быть не одна директория, а целый массив [System.IO.DirectoryInfo[]] если у юзера есть профили на нескольких компах.
 
 
 
 
Добавлено:
 
Писать функцию кидаться сразу на надо: отпишитесь прежде, что поняли, и что вас по-прежнему тревожит.
У меня вот есть основания для сомнений, возможно чуток изменим спецификацию.

Всего записей: 17163 | Зарегистр. 14-10-2001 | Отправлено: 17:21 08-03-2018 | Исправлено: LevT, 18:24 08-03-2018
LevT



Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
ЗЫ. Групповые папки на файловом сервере все внутри единственной шары?
 

Код:
 
 
 
function Get-Share {
[CmdletBinding()]
param(
    [Parameter(ValueFromPipeline)]
    [Microsoft.ActiveDirectory.Management.ADGroup[]]
    $Group
)
    BEGIN {
        $Root = 'E:\Shares\Personal\Temp'
    }
    PROCESS {
        $path = Join-Path $root $_.Name  
        $path  
    }
}
 
 
function Update-Share {
[CmdletBinding()]
param(
    [Parameter(ValueFromPipeline)]
    [string]$Path,
    [Microsoft.ActiveDirectory.Management.ADGroup]$Group
)
 
    PROCESS {
        If ($false -eq (Test-Path $_)) {
            New-Item -Path $_ -Name $Group.Name -ItemType Directory  
        }
     
        $path | Update-SharePermissions $Group
    }
 
}
 
Get-Groups -PipelineVariable Group |
    Get-Share |  
        Update-Share
-Group $Group
 
 

 
 
Осталось написать две функции:

Код:
 
Update-SharePermissions{
[CmdletBunding()]
param(
      [Parameter(ValueFromPipeline)]
      [string]$Path,
      [Microsoft.ActiveDirectory.Management.ADGroup] $Group
)
.....
}

 
и  
 

Код:
 
Update-Shortcut {
[CmdletBinding()]
param(
    [Parameter(ValueFromPipeline)]
    [MyType.UserDesktopInfo]$UserDesktopInfo,
    [string]$TargetPath
)  
....
}

 
 
В параметр $UserDesktopInfo следует загнать все пароли и явки, нужные для для добавления ярлыков на юзерский десктоп (не факт, что хватит UNC пути)
 

Всего записей: 17163 | Зарегистр. 14-10-2001 | Отправлено: 20:02 08-03-2018 | Исправлено: LevT, 20:36 08-03-2018
serik1986



Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
LevT
на счет шары для создаваемых по аналогии с группами, ДА, есть одна шара на сервере где и будут они все формироваться/обновляться.
 
На счет вообще всей реализации, извиняюсь сразу за ламерский текст, просто я только только перевариваю синтаксис и для меня это пока как пазл который я пытаюсь собарть воедино.
У меня скорее парочка вопросов, возможно ли данный код использовать в качестве единого скрипта (в голове звучит что конечно же можно) но я задаю этот вопрос скорее чтоб уточнить правильно так делать или нет?
Другой вопрос касается того, что пользователи у нас все таки имеют входы часто с разных машин и мы не используем роуминг профилей, т.к. просто места не хватит на сервере или выделенной машине для всех пользователей. Я искал когда то решение проблем с местом под профильские директории в случае роуминга, но кроме как ограничение квотой ничего не нашел, а т.к. юзеры хранят массы данных на рабочем столе то при логофф все это будет сохранятся на сервере и когда то просто может возникнуть проблема не сохраненных данных если есть ограничение по квоте. Если у вас есть какая то рекомендация по этому поводу готов прислушаться... но пока мы путями для профилей не пользуемся, соответственно ветка кода

Код:
$profile = $_.ProfilePath | Get-Item    #не знаю как у вас, а в нашей АД в этом месте бардак, и данных AD может быть вовсе даже недостаточно  

вероятнее всего вернет пустое значение...
да и в добавок к сказанному мы пользуемся только home folder которую ссылаем на общую папку на сервере в которой ограничили место до 5ГБ и по расширениям хранимых файлов только на документы офисного характера, так сказать локальное облако для пользователей которые часто сидят на разных местах и им требуется всего лишь excel или word, либо важные личные документы, с гарантией хранения на сервере а не локально.
 
и еще ветка кода функции которую я не до конца понял, прошу объяснить:
в функции Get-Share:

Код:
 BEGIN {
        $Root = 'E:\Shares\Personal\Temp'
    }  

Я это понимаю как создание переменной $Root с постоянным путем к корневой shared папки в которой и будут жить все остальные... может ошибаюсь, но зачем это делать если можно просто где то один раз присвоить к $Root значение пути и пользоваться им.
 
в остальном я погуглил команды и аргументы используемые в коде, немного туман стал рассеиваться и я кажись стал понимать структуру синтаксиса, чуть позже выложу свой вариант Update-SharePermissions, а то что касается Update-Shortcut а именно MyType.UserDesktopInfo я пока не знаю как быть...

Всего записей: 267 | Зарегистр. 29-06-2009 | Отправлено: 13:52 09-03-2018 | Исправлено: serik1986, 13:54 09-03-2018
LevT



Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору

Цитата:
У меня скорее парочка вопросов, возможно ли данный код использовать в качестве единого скрипта (в голове звучит что конечно же можно) но я задаю этот вопрос скорее чтоб уточнить правильно так делать или нет?  

 
Просто разместить всё подряд на одной простыне скрипта.
Вызовы функций должны располагаться ниже их определения.
 
 
Добавлено:

Цитата:
Другой вопрос касается того, что пользователи у нас все таки имеют входы часто с разных машин и мы не используем роуминг профилей, т.к. просто места не хватит на сервере или выделенной машине для всех пользователей.

 
Роуминг профили на самом деле дрянь! (в любых реальных российских и СНГ условиях)
если нет нужды волочь это "добро" из-за прежних админов падких на халяву - то радуйтесь, что его у вас нет.
 
Для разрозненных компов - либо попытаться достать юзерские папки-десктопы админской костлявой рукой, либо логон скрипты как вы планировали.
Ваш вариант хорош тем, что не надо париться о том, чтобы  подопытные компы были включены.
 
 
 
Добавлено:

Цитата:
и еще ветка кода функции которую я не до конца понял, прошу объяснить:  

 
Это корень папки на файловом сервере, где создаются подпапки для групп.
(доступны они из локалки через единственную шару \\srv-fs\Personal - в МОЁМ ТЕСТОВОМ ОКРУЖЕНИИ)
 
Не создание этой папки, а определение переменной, один раз перед тем как гонять внутренний цикл.
 
 

Всего записей: 17163 | Зарегистр. 14-10-2001 | Отправлено: 13:53 09-03-2018 | Исправлено: LevT, 20:23 09-03-2018
LevT



Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
serik1986

Цитата:
 а именно MyType.UserDesktopInfo я пока не знаю как быть...

 

Код:
 
$UserDesktopInfo = [PSCustomObject]@{
    PSTypeName = 'MyType.UserDesktopInfo'
    ComputerName  = 'room2-446-4'
    Profile   = 'ABogdanova'
    Username      = 'DOMAIN\Cooladmin'
    Password = 'P@ssw0rd'
}
 

 

Код:
 
$TypeData = @{
    TypeName = 'MyType.UserDesktopInfo'
    MemberType = 'ScriptProperty'
    MemberName = 'ProfileDesktopPath'
    Value = {"C:\Users\{0}\Desktop" -f $this.Profile}
}
Update-TypeData @TypeData
 
 
[PS]> $UserDesktopInfo
 
ComputerName   : room2-446-4
Profile        : ABogdanova
Username       : DOMAIN\Cooladmin
Password       : P@ssw0rd
ProfileDesktopPath  : C:\Users\ABogdanova\Desktop
 

Всего записей: 17163 | Зарегистр. 14-10-2001 | Отправлено: 20:08 09-03-2018 | Исправлено: LevT, 22:38 09-03-2018
serik1986



Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
LevT
извините за долгое отсутствие, были другие задачи не мог к этой вернуться... сейчас установил себе на комп RSAT пакет для windows 10, буду экспериментировать с PS и AD у себя на компе.
сейчас изучаю принцип работы отладчика PS ISE чтоб на точках остановки смотреть результаты...

Всего записей: 267 | Зарегистр. 29-06-2009 | Отправлено: 09:21 15-03-2018
LevT



Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
serik1986
это всё замечательно, но (судя по себе) легко утратить фокус и не доделать начатое
чтобы была возможность помочь - лучше попробуйте проделать то, что мы обсуждали здесь выше и доложиться о том, что конкретно не получается
 
 
Добавлено:
 
И да, играться с AD имеет смысл там, где есть сама подопытная AD (а не одноразовася песочница в виртуалках).
Кмк, всё что было нужно от AD, делают представленные здесь выше функции

Всего записей: 17163 | Зарегистр. 14-10-2001 | Отправлено: 09:29 15-03-2018
serik1986



Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
LevT
я так и сделал, мой компьютер в сети AD и я пока временно создал шару на своем компе, чтоб протестировать аналогию с файл сервером.
из результатов следующее...

Код:
Get-Group -PipelineVariable Group |
    Get-Share |  
        Update-Share -Group $Group  

Данная процедура практически отрабатывает все. имею ввиду читаются AD группы по фильтру и создаются соответствующие папки в корневой. Сейчас буду искать в инете какой командой задать пермишены папки согласно соответствующей секьюрити группы.
если напишите как правильно буду признателен, а может и сам найду до того времени...

Всего записей: 267 | Зарегистр. 29-06-2009 | Отправлено: 13:23 15-03-2018
LevT



Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
serik1986
мне тоже нужно гуглить: так что напомните, если отчаятесь сделать самостоятельно
 
Что касается видимости клиентам только нужных шар - попробуйте потом включить на родительской шаре Access-Based Enumeration: так оно выйдет фэншуйней, чем городить отсебятину.

Всего записей: 17163 | Зарегистр. 14-10-2001 | Отправлено: 14:13 15-03-2018 | Исправлено: LevT, 14:15 15-03-2018
serik1986



Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
LevT
как раз зашел на огонек)  
за 2 часа сделал почти рабочую функцию Update-SharePermissions.
Код такой получился:

Код:
function Update-SharePermissions{
[CmdletBinding()]
param(
    [Parameter(ValueFromPipeline)]
    [string]$Path,
    [Microsoft.ActiveDirectory.Management.ADGroup[]]$Group
)
 
PROCESS {
$acl = get-acl $Path
$isProtected = $true  
$preserveInheritance = $false
$acl.SetAccessRuleProtection($isProtected, $preserveInheritance)  
Set-Acl -Path $Path -AclObject $acl  
 
 
$Ar = New-Object system.security.accesscontrol.filesystemaccessrule((get-adgroup $Group).sid,"FullControl", "ContainerInherit, ObjectInherit", "None", "Allow")
$Acl.SetAccessRule($Ar)
Set-Acl -Path $Path -AclObject $Acl
}
 
}  

 
проблема в следующем...
на месте
Код:
New-Object system.security.accesscontrol.filesystemaccessrule((get-adgroup $Group).sid
powershell ругается мол Get-ADGroup : Cannot validate argument on parameter 'Identity'. The argument is null. Provide a valid value for the argument, and then try running the command again.
я так понимаю почему то $Group пустой, только вот почему?

Всего записей: 267 | Зарегистр. 29-06-2009 | Отправлено: 15:15 15-03-2018
LevT



Platinum Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
serik1986
Я с AD буду завтра, но навскидку скажу, что  

Код:
Get-ADGroup $Group  

это масло масляное!
 
$Group поданная на вход этого командлета является полноценным объёктом типа ADGroup  
(Get-ADGRoup уже вернул его выше по трубе)
 
Так что просто $Group.sid  

Всего записей: 17163 | Зарегистр. 14-10-2001 | Отправлено: 15:34 15-03-2018 | Исправлено: LevT, 15:43 15-03-2018
serik1986



Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
LevT
да пробовал и так и этак, ps ругается и подчеркивает именно $Group
 
если просто $Group.sid
то ругается:
New-Object : Exception calling ".ctor" with "5" argument(s): "Value cannot be null.
Parameter name: identity"
 
Добавлено:
хотелось бы еще пару подсказок на будущее... т.к. я раньше пограммировал на 1с немного, то там пользовался отладчиками... и при точке останова мог рассматривать все результаты полученные до точки.
здесь сколько не пытался не могу понять как мне например остановившись в цикле увидеть какие параметры я имею... где мне их отлаживать то?) явно не туда тыкаю, просто так и не смог найти...
 
 

Всего записей: 267 | Зарегистр. 29-06-2009 | Отправлено: 15:40 15-03-2018 | Исправлено: serik1986, 15:46 15-03-2018
Открыть новую тему     Написать ответ в эту тему

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Компьютерный форум Ru.Board » Компьютеры » Прикладное программирование » Windows PowerShell 1.x/2.x/CTP


Реклама на форуме Ru.Board.

Powered by Ikonboard "v2.1.7b" © 2000 Ikonboard.com
Modified by Ru.B0ard
© Ru.B0ard 2000-2024

BitCoin: 1NGG1chHtUvrtEqjeerQCKDMUi6S6CG4iC

Рейтинг.ru