parafoxer: (Foxic)
Больше для себя. Но вдруг кому поможет.

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

Условия:

AD
WIndows 2008 R2
Powershell_ise
модуль NTFSSecurity для powershell
файловая шара  для создания папок \\studsrv\students

1. Создаем CSV файл в кодировке Unicode, где описываем в столбцах нужные параметры. Например создадим 4 студентов:

#имена столбцов
Name,Password,Surname,GivenName,DisplayName,Description,Department,profilePath,homeDirectory,Title,Division,City,ScriptPath,SamAccountName                                           
#содержимое столбцов
students14st30,dofbwut,Ivanova,Alena,Иванова Алёна Юрьевна,Студент_с_2014_года,students-14,\\dc1\profiles\student.man,\\studsrv\students\students14\students14st30,Студент,students-14,Perm,start_st.bat,students14st30
students14st31,jghwpty,Petrov,Nikolai,Петров Николай Сергеевич,Студент_с_2014_года,students-14,\\dc1\profiles\student.man,\\studsrv\students\students14\students14st31,Студент,students-14,Perm,start_st.bat,students14st31
students14st32,nkfroqw,Sidorov,Bogadn,Сидоров Богдан Станиславович,Студент_с_2014_года,students-14,\\dc1\profiles\student.man,\\studsrv\students\students14\students14st32,Студент,students-14,Perm,start_st.bat,students14st32
students14st33,lkdtwqe,reserv,reserv,reserv,Студент_с_2014_года,students-14,\\dc1\profiles\student.man,\\studsrv\students\students14\students14st33,Студент,students-14,Perm,start_st.bat,students14st33

более подробно см. http://parafoxer.livejournal.com/106150.html или по тегу powershell

2. Называем и размещаем этот файл C:\scripts\students\students-14.csv
3. Открываем Powershell ISE и копируем туда код:

#Разрешаем скрипты, импортируем модуль
Set-ExecutionPolicy Unrestricted -force
import-module activedirectory
#создаем кучу пользователей
Import-CSV -Path "C:\scripts\students\students-14.csv" | ForEach-Object -process {New-ADuser -Name $_.Name -Surname $_.Surname -City $_.City -Department $_.Department -profilePath $_.profilePath -homeDirectory $_.homedirectory -GivenName $_.GivenName -Title $_.Title -Description $_.Description -DisplayName $_.DisplayName -Division $_.Division -ScriptPath $_.ScriptPath -SamAccountName $_.SamAccountName -Path "OU=Student,OU=Students_OU,DC=domain,DC=gorod,DC=ru" -CannotChangePassword $true -ChangePasswordAtLogon $false -PasswordNotRequired $true -AccountPassword (ConvertTo-SecureString $_.Password -AsPlainText -Force) -Company domain_gorod_students}
Start-Sleep -s 5
#создаем группу безопасности для этих пользователей
New-AdGroup -Name students-14 -SamAccountName students-14 -Description "Группа студентов students-14" -GroupCategory Security -GroupScope Global -Path "OU=Student,OU=Students_OU,DC=domain,DC=gorod,DC=ru"
Start-Sleep -s 5
#добавляем туда всех этих пользователей
Get-ADUser -filter {(Department -eq "students-14")} | ForEach-Object -process {Add-ADGroupMember -identity "students-14" -Members $_.SamAccountName}
Start-Sleep -s 5
#добавлем группу пользователей в общую группу ВСЕХ пользователей   - в группу Students
Add-ADGroupMember Students students-14
Start-Sleep -s 5
#создаем для группы папку, в которой будут храниться личные папки пользователей
Get-ADgroup students-14 | Sort-Object -Property Name | Select-Object -Property sAMAccountName | foreach {
$folderName = $_.SamAccountName
$Dir = "\\studsrv\students\"
New-Item -ItemType directory -Path $Dir -Name $folderName}
Start-Sleep -s 5
#импортируем модуль ntfssecurity (подробнее см. http://parafoxer.livejournal.com/188293.html) и создаем для каждого пользователя личную папку, именую ее именем пользователя (samAccountName) и даем на них полные права администраторам (user1, user2, user3)
import-module ntfssecurity
Get-Item \\STUDSRV\students\students-14| Add-Ace -Account domain\user1 -AccessRights FullControl
Get-Item \\STUDSRV\students\students-14| Add-Ace -Account domain\user2 -AccessRights FullControl
Get-Item \\STUDSRV\students\students-14| Add-Ace -Account domain\user3 -AccessRights FullControl
Start-Sleep -s 5
$rootDir = "\\studsrv\students\students-14\"
Get-ADUser -filter {(Department -eq "students-14")} | foreach {
$folderName = "$($rootDir)$($_.Department)\$($_.SamAccountName)"
New-Item -ItemType directory -Path $folderName}
Start-Sleep -s 5

4. Назначаем каждому пользователю нужные права с использованием функционала ntfssecurity. Обратите внимание - для каждого пользователя выпоняется своя команда. Назначение прав просто через powershell без модуля ntfssecurity гораздо сложнее - там всего 2 команды get-acl \ set-acl а все остальное  - куча методов, осваивать которые желания нет. Шаблон такой команды в экселе создать несложно, заменять и продлять требуется только номера пользователей.

Get-Item \\STUDSRV\students\students-14\students14st30 | Add-Ace -Account hse\students14st28 -AccessRights Modify, Synchronize
Get-Item \\STUDSRV\students\students-14\students14st31 | Add-Ace -Account hse\students14st29 -AccessRights Modify, Synchronize
Get-Item \\STUDSRV\students\students-14\students14st32 | Add-Ace -Account hse\students14st30 -AccessRights Modify, Synchronize
Get-Item \\STUDSRV\students\students-14\students14st33 | Add-Ace -Account hse\students14st30 -AccessRights Modify, Synchronize

т.к. модуль ntfssecurity уже импортиорван (п.3) выполняем команды сразу

5. Итог - куча октлюченных (!не забыть включить) пользователей, в группе, с папками, с правами
parafoxer: (Foxic)
Создать папку или получить такие ее параметры как разрешения безопасности позволяет стандартный powershell. Но вот с выставлением разрешений там полная маета, связанная с тем, что надо углубляться в дебри классов-объектов, а нормальному админу это нафиг не сдалось, иначе не был бы он админом, а был бы программистом. ПОэтому программисты написали некую штуку, под навазнием File System Security PowerShell Module 2.4. Об опыте использования этой штуки и пойдет речь.


опыт использования File System Security PowerShell Module 2.4 )
parafoxer: (Foxic)

Такое дебильное название, но зато поисковикам хорошо))) НИЧЕГО дельного, а главное - простого!!! в инете не нашел, какие-то куски, решения тупо нет. Вот не понимаю - неужели никто этого не делает? Какие-то безумно сложные решения конечно есть, портянки по поллиста, но нафига из пушки по воробьям палить, если есть наш любимый конвейер и экспорт в csv, делающий процесс изменения может не самым быстрым, зато внятным)))

Как обычно мануальчик будет самый понятный, чтобы даже самый начинающий администратор AD мог понять и применить.

Итак, требуется сменить путь к домашней папке пользователя в AD. Точнее у целой кучи пользователей. Можно менять и любой другой параметр. Описанный путь не самый удобный и автоматизированный, зато понятный и не требует зверских напряжений по разбору кода.
Каждый объект в AD обладает набором атрибутов (свойств). Нам нужно сменить имя сервера в пути к домашней папке пользователя - это атрибут homedirectory. Где посмотреть доступные атрибуты? Можно через консоль mmc, свойства объекта (пользователя), вкладка "Редактор атрибутов":

change_stud_param01




Если эта вкладка не отображается - в консоли щелкаем меню "Вид" и отмечаем строку "Дополнительные компоненты"
Также свойства пользователя можно получить с помощью команды get-aduser, но тут мы уже и подошли к делу))

1. Запускаем powershell, разрешаем запуск скриптов (параноики, задроченые мыслями о мега-безопасности идут лесом, или учить как выстраивать ДМЗ и рулить файрволами)))

Set-ExecutionPolicy Unrestricted


2. Импортируем модуль AD командой:

Import-Module ActiveDirectory

3. Получаем список всех пользователей из определенного OU в формате csv, фильтруя полученные результаты по свойствам, сортируя их по имени и выбирая только нужные нам параметры - sAMAccountName,homeDirectory

Get-ADUser -SearchBase "OU=Student,OU=Students_OU,DC=domain,DC=ru" -Filter * -Property * | Sort-Object -Property Name | Select-Object -Property sAMAccountName,homeDirectory | Export-CSV -Path C:\stud.csv

Разберем детально:
Get-ADUser -SearchBase "OU=Student,OU=Students_OU,DC=domain,DC=ru" - даем задачу команде Get-ADUser с параметром -SearchBase получить все объекты в некоем OU в AD. Чтобы не ошибиться и правильно прописать свойства OU, из которого нужно получать объекты, смотрим свойства этого OU также через редактор атрибутов, атрибут называется distinguishedName (епт, язык сломаешь))):

change_stud_param02



-Filter * -Property * - фильтруем  полученные объекты, нам нужны все (там у нас только пользователи, если у вас в одном OU все напихано - и компы и люди и кони  - вводите какой-нибудь фильтр, или перемещайте в отдельный OU (рекомендуется)))

| Sort-Object -Property Name- передаем в конвейер полученные данные и сортируем их по свойству "Имя" иначе будет бардак в файле экспорта

| Select-Object -Property sAMAccountName,homeDirectory  - передаем в конвейер свойства-атрибуты выбранных объектов, нужные нам - аккаунтнэйм и домашнюю папку. Можно добавить другие свойства-атрибуты, которые вам требуются.

| Export-CSV -Path C:\stud.csv - передаем в конвейер экспорта в файлик полученные данные

4. Редактируем полученный список C:\stud.csv, и приводим его вот в нужный нам вид (в моем случае это 2 столбца, 2 значения):
sAMAccountName,homeDirectory
student0001,\\fileserver002\students\student0001

Первая строка - перечисления параметров-атрибутов через запятую
Вторая строка - перечисления значений этих параметров через запятую
С редактированием файлика думаю проблем нет - открываем в экселе, или файловом менеджере и меняем все автозаменой.
Сохраняем файлик ОБЯЗАТЕЛЬНО в формате Unicode!!! powershell любит юникод)))

5. Импортируем отредактированный список в АД

Import-CSV -Path "C:\stud.csv" | ForEach-Object -process {Set-ADuser -Identity $_.sAMAccountName -homeDirectory $_.homedirectory}

Разберем детально:
Import-CSV -Path "C:\stud.csv" - импортируем данные из нашего файлика

| ForEach-Object -process - передаем данные в конвейер, указывая, что для каждого объекта выполняем команду, указанную в скобках { }

{Set-ADuser -Identity $_.sAMAccountName -homeDirectory $_.homedirectory} - в скобках указываем команду установки атрибутов set-aduser, идентифицируем пользователя по аккаунтнэйм -Identity $_.sAMAccountName и указываем что заменяем мы параметр homeDirectory на тот, который указан в файлике.

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

parafoxer: (Foxic)
   Опять понадобилось и НИЧЕГО нет готового Все пишут как забацать контакты с помощью консоли MS Exchange 2007 \ 2010. А вот бывают ситуации - контроллер домена Win2008, а Exchange- 2003. Дурдом, но имеет место быть, что ж делать... И вот требуется создать там  примерно 6000 контактов. Просто контакт создать несложно, но вот атрибуты прописать, те которые требуются Exchange для работы с контактами - задача еще та.
  Итак, требуется создать кучу почтовых контактов средствами powershell v. 2.0.1.1 с использованием модуля работы с AD. Попытаюсь, как обычно, описать самым простейшим языком, понтяным самому неопытному администратору.

1. Создаем файл в MS Excel с именем contacts_list, сохраем в формате CSV по пути С:\CSV, и именуем в файле столбцы вот так:

Name Mail mailNickname Type proxyAddresses targetAddress

в принципе этих параметров хватает для создания полноценного контакта и Exchange его видит, и может с ним работать, в какой бы папке-OU  в вашем AD  он у вас не был бы.
   Какие конкретно поля в свойствах объекта "контакт" отражают эти столбцы?
   Вот разъяснения, типа табличка)))

   Параметр столбца - Название в редакторе атрибутов ADSI (пояснение) - Русскоязычное обозначение на свойствах контакта

   Name - CN (каноническое имя объекта) - Имя
   Mail - Mail (электронная почта) - Эл.почта
   mailNickname - mailNickname (алиас Exchange, псевдоним) - отображается только в редакторе атрибутов
   Type - ObjectClass (класс (тип) объекта) - отображается только в редакторе атрибутов
   proxyAddresses - proxyAddresses (адрес внешней по отношению к домену электропочты в формате SMTP:address@domain.ru) - отображается только в редакторе атрибутов
   targetAddress - targetAddress (адрес внешней по отношению к домену электропочты в формате SMTP:address@domain.ru) - отображается только в редакторе атрибутов
  Заполняем столбцы, например

Name Mail mailNickname Type proxyAddresses targetAddress
Vasiliy Terkin vasil@rambler.ru Partners_Sales_0001 contact SMTP:vasil@rambler.ru SMTP:vasil@rambler.ru


Примечание:
mailNickname должен отображать принадлежность к какой-либо группе рассылки, и лучше, если будет иметь порядковый номер. Встречал глюки, когда все контакты имели одинаковый mailNickname и глюки были неприятные и странные.
proxyAddresses, targetAddress обязаельно должные быть в указанном формате SMTP:adres@domain.ru, иначе Exchange не поймет контакта и будет выдавать ошибку о неверном формате.

2. Создаем файл с create_contact и расширением ps1 и  копируем туда вот такой код:

Import-CSV -Path "C:\CSV\contacts_list.csv" | ForEach-Object -process {New-ADObject -Path "OU=PostContact,DC=domain,DC=corp,DC=local" -Name $_.Name -Type $_.Type -DisplayName $_.Name -OtherAttributes @{'Mail'=$_.mail; 'proxyAddresses'=$_.proxyAddresses; 'targetAddress'=$_.targetAddress; 'mailNickname'=$_.mailNickname}}

Что тут куда? Разберем по кускам:

Import-CSV -Path "C:\CSV\contacts_list.csv" - команда забирает данные из файла расположенного по пути C:\CSV\contacts_list.csv

| ForEach-Object -process { - и передает данные в конвейер обработки, причем каждое значение обрабатывается отдельно в соответствии с именами столбцов

New-ADObject  - сам конвейер представляет собой команду создания в AD объекта (справка в powershell по вызову get-help new-adobject - full)

-Path "OU=PostContact,DC=domain,DC=corp,DC=local" - путь, по которому будет создан почтовый контакт. Посмотреть его можно открыв AD и щелкнув свойства OU (контейнера) и просмотрев путь во вкладе "Объект" и переделав его в соответствии с форматом  в примере. Если этот параметр убрать - контакты создадутся в Users, это путь по умолчанию.


-Name $_.Name -Type $_.Type -DisplayName $_.Name - обязательные параметры (Name и Type) и не очень обязательный -
DisplayName. Их надо создавать понятыми, можно и кириллицей, можно латинскими буквами. Есть ограничение по длине, вроде бы, точно не помню - 64 символа.

-OtherAttributes @{'Mail'=$_.mail; 'proxyAddresses'=$_.proxyAddresses; 'targetAddress'=$_.targetAddress; 'mailNickname'=$_.mailNickname}} - самое важное. Почтовые адреса нельзя передать просто так, как Name и Type. Почтовые адреса это типа otherattributes  - дополнительные атрибуты, но их также можно передать из столбцов файла .CSV. Не забывайте проверить все символы и скобки, в конце должно быть 2 скобки.

3. Сохраняем файлы и проверяем пути -C:\CSV - в файле и в реале)))
4. Открываем powershell на контроллере домена (контроллер не должен быть типа ReadOnly!!!), выполняем последовательно 2 команды:

Set-ExecutionPolicy Unrestricted

import-module activedirectory

5. Выполняем C:\CSV\create_contact.ps1
6. Наблюдаем (не забываем сделать рефреш консоли) в OU PostContact новые почтовые контакты.

Ну и напоследок, несколько советов.
- Если у вас полноценная версия powershell, то вызов из нее powershell_ise откроет очень удобный редактор скриптов с возможностью запуска и прочими удобствами.
- Файлы CSV должны быть в кодировке Unicode, если у вас ANSI - будет ошибка.
- Можно добавить еще массу столбцов и, следовательно, атрибутов, к почтовому контакту. Например, некоторым Exchange может потребоваться такой атрибут контакта, как legacyExchangeDN. Узнать его несложно - создаем руками почтовый контакт в АД, смотрим этот параметр во вкладке "Редактор атрибутов" (если этой вкладки нет - включаем ее в консоли вот так: меню Вид \ Дополнительные компоненты). Соответственно к файлу с данными добавляем столбец legacyExchangeDN, заполняем его отредактированным значением, скопированным из только что созданного контакта, а в скрипте после 'mailNickname'=$_.mailNickname добавляем
'legacyExchangeDN'=$_.legacyExchangeDN. Не забываем скобки.

parafoxer: (foxic)
Столкнулся и ничего толкового в инете не нашел. Все какие-то урывки и куски. Батник (просто BAT) у нас есть, но как-то на 2008 сервере уже несерьезно))). Решил написать его сам. Получилось.
Ну и теперь решил описать так, чтобы ЛЮБОМУ было понятно, кто хоть чуть-чуть видел powershell и знаком со скриптами.

Итак. Чтобы создать кучу юзеров с кучей параметров в Active Directory требуется (помимо Windows Server 2008 R2 SP1 \ PowerShell 2.0.1.1):

0. Разрешить выполнять скрипты в powershell - открыть powershell на контроллере домена и выполнить команд
Set-ExecutionPolicy Unrestricted





Не выполнив этой команды получим сообщение "выполнение скриптов запрещено для данной системы"

1. Загрузить в powershell модуль управления Active Directory. Выполняем команду
import-module activedirectory

2. Создаем в MS Excel файлик с параметрами пользователей.  В верхней строке указано объяснение что это за параметр. Во второй строке указано  имя параметра - это реальная команда-параметр для командлета new-aduser. Далее в каждом столбце указано значение какого-либо параметра, который будет присвоен объекту при создании. В принципе все эти параметры можно посмотреть по команде get-help new-aduser -full. Я выбрал нужные мне и задал их значения:


Кому не видно - вот перечень столбцов через запятую, которые по-моему обязательны.
Name,Password,Surname,GivenName,DisplayName,Description,Department,Title,Division,City,EmailAddress,ScriptPath,SamAccountName

Вообще можно заполнить все параметры учетки, имена параметров можно уивдеть в свойствах учетки, на вкладке Редактор атрибутов (если такой вкладки нет - включаем дполнитиельные возможности в свойствах консоли ММС)

При создании параметров нужно избегать точек, запятых и прочего мусора, который может быть воспринят как команда. Обязательным параметром следует сделать SamAccountName (спасибо комментирующему за поправку)
Сохраняем файлик с расширением XLS (XLSX - для 2007). А потом сохраняем с расширением CSV (разделители - точка с запятой). Открываем файлик с расширением CSV в блокноте и сохраняем в другой кодировке - Unicode (а по умолчанию идет ANSI, которую powershell не переваривает и при выполнении выдаст ошибку). Имя сохраняемого и путь (для упрощения понимания последующих шагов) - C:\scripts\createuserbat.csv. Открываем файлик в каком-нибудь файловом менеджере и заменяем ВСЕ точки с запятой (;) на просто запятые - (,). Сохраняем. Не должно быть лишних пробелов, точек и прочего хлама. Проверять нужно тщательно.

3. Открываем блокнот и вставляем туда вот этот код:
Import-CSV -Path "C:\scripts\createuserbat.csv" | ForEach-Object -process {New-ADuser -Name $_.Name -Surname $_.Surname -City $_.City -Department $_.Department -GivenName $_.GivenName -Title $_.Title -Description $_.Description -DisplayName $_.DisplayName -Division $_.Division -EmailAddress $_.EmailAddress -MobilePhone $_.MobilePhone -SamAccountName $_.SamAccountName -ScriptPath $_.ScriptPath -Path "ou=Users_Test,dc=Test,dc=ru" -CannotChangePassword $true -ChangePasswordAtLogon $false -PasswordNotRequired $true -AccountPassword (ConvertTo-SecureString -AsPlainText $_.Password -Force) -Company TEST}

Теперь подробнее. Разберем скрипт на куски:
Import-CSV -Path "C:\scripts\createuserbat.csv" - эта команда берет данные из файлика, котоый мы создали (и положили по указанному пути - в данном случае в C:\scripts\createuserbat.csv) и передает их...
| ForEach-Object -process - ... в конвейер указанной далее команды (т.е. указанная далее команда отработает для всех строк нашего createuserbat.csv)
{New-ADuser - команда уже знакомая и понятная - она создает пользователя с нужными атрибутами, которые перечисляются далее...
-Name $_.Name - это атрибут "Имя" (по сути логин пользователя). Т.е. мы говорим команде New-ADUser взять параметр Name из файлика createuserbat.csv из столбца Name (указывается псевдоним $_.Name).
Далее - все по аналогии. Обязательным параметром следует сделать SamAccountName

Нюансы - куда создается объект, его пароль и атрибуты, связанные с паролем. А также скрипт, выполняющийся при входе в систему.

Куда создается объект (пользователь)?
Это указывается параметром -Path "ou=Users_Test,dc=Test,dc=ru" из которого мы видим, что создаваться он будет в контейнере (OU) Users_Test домена Test.ru. Тут надо подставить свое значение конечно. Я бы советовал держать пользователей не в Users, как это бывает по умолчанию, а в другом OU. Это упростит потом работы с политиками. Посмотреть путь до контейнера можно в консоли MMC Пользователи и компьютеры со включенными дополнительными параметрами. Смотрим в редактор атрибутов, параметр distinguishedName.

Пароль и его атрибуты.
-CannotChangePassword $true  - задаем параметр "Запретить смену пароля пользователем"

-ChangePasswordAtLogon $false - задаем параметр "Сменить пароль  при следующем входе в систему" в значение НЕТ

-PasswordNotRequired $true - задаем параметр "Требуется ли пароль для учетной записи" в значение ДА

-AccountPassword (ConvertTo-SecureString -AsPlainText $_.Password -Force) - задаем собственно сам пароль, включая возможность это делать из простого текстового значения, снимая атрибуты секретности, и передавая в конвейер значение столбца Password в файлике createuserbat.csv

Эти три параметра рекомендую не менять - они зависят друг от друга (уже забыл как))) и надо просто их выполнить именно так)))

Скрипт, выполняющийся при входе в систему.
-ScriptPath $_.ScriptPath
В параметре прописано startuser.bat. Это обычный батник, которым очень удобно подключать сетевые диски, запускать какие-то уведомлялки на js, и прочая. Лежать должен в \\DomainController\NETLOGON.

Сохраняем файл с расширением PS1 в кодировке Unicode с именем CreateUser.PS1 в тот же каталог, куда и createuserbat.csv

4. Запускаем файл CreateUser.PS1

5. Учетные записи готовы, если их не видно в AD - обновите страницу консоли))) Однако все они выключены.   Выделяем их все и включаем одной командой по правой кнопке мыши. В принципе есть параметр -Enabled, использованного нами командлета New-ADUser, и ее можно добавить в конец списка параметров, но мне кажется удобнее включать учетные записи когда пользователь придет к администратору (т.е. ко мне) за листочком с учетными данными.

Есть и другие варианты создания пользователя  - с помощью questsoft и т.п., но если у вас Windows Server 2008 R2 SP1 \ PowerShell 2.0.1.1 - это работает, проверено.

UPDATE 1
Всегда заменяйте разделители  - точки с запятой (;) на запятые(,)
UPDATE 2
Всегда проверяйте колчиество симоволов в пароле - одно должно соответствовать количеству символов в пароле, указнному в Default Domain Policy
UPDATE 3
Обязательным параметром следует сделать SamAccountName. Сделайте его равным параметру Name (т.е. логину)
UPDATE 4
Кроме полей "описание" все остальные поля рекомендуется заполнять латинскими буквами, без пробелов, например buhgalteria_permskogo_otdelenia_banka
UPDATE 5
Для выполнения очень удобно использовать не стандартную строку powershell, а некий giud, встроенный в ОС и позволяющий боле удобно править скрипты, содвать странички и пр пр. Запускается просто: выполнить \ вводим
powershell_ise
и энтер.

Profile

parafoxer: (Default)
parafoxer

September 2025

S M T W T F S
 123456
78910111213
14151617181920
21 222324252627
282930    

Syndicate

RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Dec. 13th, 2025 12:40 am
Powered by Dreamwidth Studios