Or: letting my wife see my personal calendar.

So yes, I keep all my personal calendar items in the totalnetsolutions.net O365-hosted account calendar. But that doesn’t stop our family from having the calendar sharing problems that apps like GetClockwise https://www.getclockwise.com/ Cozi https://www.cozi.com/ or even shared Google or iCloud calendars try to solve.

The problems we ran into with Cozi were that we had to actually put the items there, then subscribe to the Cozi calendar from everywhere, when most of the time i’m looking at a calendar, I want to look at a single calendar. Can I agree to host this PTO event, or is my wife going to be out of town? Seeing the free/busy from her calendar, my calendar, etc. in one place got difficult.

So I went back to basics: Exchange can publish free/busy data. If everyone is an O365 subscriber, can’t we just share cross-organization? And the answer is that yes we can… IF the organization allows it! Since I am the admin for the TNS organization, I can share my calendar out, and not have to forward events everywhere. here’s how:

First, the admin has to follow the steps here: https://docs.microsoft.com/en-us/office365/admin/manage/share-calendars-with-external-users?view=o365-worldwide – Log into the Admin Center, click “Show all”, then “Settings” and finally “Serivces & add-ins”. The list of add-ins will change (as of today it includes Azure MFA, Calendar, Cortana, Directory Synchronization, and a host of other services), but you’re looking for “Calendar”. Click that and you’ll get this pane slide in from the left:

O365 Admin Center Calendar Sharing Settings

Click “Let your users share their calendars with people outside of your organization who have Office365 or Exchange” and “Save Changes”.

BUT WAIT, THERE’S MORE! Now click “Go to the Exchange admin center to manage additional settings”, and click “organization”:

O365 Admin Center Organization Sharing page

From here, under the “individual sharing” section you can create a new policy (which has to be assigned to users), or hit the pen to edit he “Default Sharing Policy” and get this page, where you can add the domain you want, and the amount of data to allow users to share (up to and including):

O365 Sharing Rule for Default Policy

Once that’s shared, you can save everything and log out. Now it’s up to the individual users to follow the settings here:

https://support.office.com/en-us/article/share-your-calendar-in-outlook-on-the-web-7ecef8ae-139c-40d9-bae2-a23977ee58d5#bkmk_beta

But realize that private events will NOT be visible in a shared calendar view. You’ll be able to load the free/busy data when scheduling, but not see the events in an overlay, even if you allow greater organizational sharing (as I have in the screenshot above). Since my wife’s work, and my other work account are both O365 tenants, I was able to share more-relaxed versions of my calendar with both organizations, send to the individual email addresses, and now we can see synchronized calendar overlays in our own work Outlook calendars.

A customer of an AD Bridge product ( https://github.com/BeyondTrust/pbis-open ) asked me:

What is the best practice around how to ensure the Users you want to “export” are available to define with PBIS settings in the named cell on the RESOURCE side. Essentially, what prerequisite needs to be met so from the RESOURCE side, we can see these users. Is it a universal group?

If it is a universal group, is the expectation that the admins of the USER domain would know when onboarding a user that requires linux access, to put them in that group on their side (the USER side) so they’re available for cell enabling on the RESOURCE side?

a Typical 1-way trust setup has users in the “USER” domain, and the computers joined to the “RESOURCE” domain.  We’ll use those names, but “RESOURCE” could be a DMZ zone, or a partner system, or anything else.  For this discussion, we’ll use the following 2 forests:
ROOT.LOCAL
USER.ROOT.LOCAL

RESOURCE.LOCAL

RESOURCE has a 1-way outbound trust to USER (RESOURCE trusts USER, but accounts in RESOURCE cannot access the USER or ROOT domains. ROOT users cannot log into RESOURCE either)

In Windows, there are 4 kinds of groups ,with different purposes and limitations.  These limitations change slightly depending on the AD forest functional level (nesting is much more restrictive in older Forest Functional levels).  This document describes the AD groups: https://technet.microsoft.com/en-us/library/dn579255(v=ws.11).aspx but to recap the AD group types are “Domain Local”, “Domain Global”, and “Universal”. The 4th is “Computer Local Group” which you manage in the “Local Users and Groups” plugin to the “Computer Management” snap-in in the Windows OS (not in AD).  On Linux, this last one equates somewhat to groups in /etc/group.

  • Universal Groups: can contain any: Domain Global group, Universal Group, or User/Computer account in the same AD forest as the Universal Group.  Universal Groups are stored in the Global Catalog, making updates to them slower than other group types.  You can use them to control rights on any resource anywhere in the forest.
  • Domain Global Groups: can contain any Domain Global group or User/Computer account from the same Domain as the Domain Global group. Domain Global groups can be used to control rights on any resource anywhere in the forest.
  • Domain Local Groups: can contain pretty much any Group from any trusted domain, including across 1-way trusts. Domain Local groups can ONLY go into Domain Local groups in the same domain, or Computer Local groups in Computers on that Domain.  Domain Local groups can only be used to control rights on a resource in the same domain as the local group.

Of note: Universal groups store (in the AD database) a DN reference, which is part of why they can only contain objects form the same domain.  Domain Local groups store a SID reference, which is why they work across one-way trusts. (Domain Local Group membership contains a “foreignKeyReference” as the members, whereas Universal Groups contain a link to the GC object in the DIT which is expanded to the DN of the object on retrieval (meaning that if you move the member, the Universal Group membership doesn’t need to be updated, because the UUID of the object referenced by the link didn’t change).

Think of it this way: Users go into Universal and Domain Global groups.  Domain Global groups go into Domain Local Groups.  Domain Local groups are used to control access to Local resources in the Domain.  What this means is that if USER\rob is in the Domain Local group USER\dlg1, and accesses a server file01.root.local: file01 doesn’t even see that USER\rob is in USER\dlg1, because USER\dlg1 isn’t in the ROOT domain that file01 is in.  AD doesn’t even bother returning any foreign Domain Local groups in the Kerberos Ticket PAC (in the TGS) to file01, since that group can’t be used to control resources outside of the USER domain.

For any other 1-way-enabled AD Bridge like PBIS or Samba, then, which groups can we provision into the cell / Computers in RESOURCE?  PBIS specifically is less restrictive than AD (samba is not), and will allow you to import the Domain Global and Universal, and even if you try hard enough, the Domain Local groups from USER into the cell in RESOURCE, and use LDAP calls to attempt to resolve the Universal and Domain Global groups and their membership, because everything I just stated above is pretty difficult to explain to a Unix admin on a tech support call. In other words: the BeyondTrust PBIS Product will export the USER Domain Local groups to the RESOURCE domain computers, so that the Unix admins don’t have to know anything in this post, but the Samba admins will need to grok all of this.

But, when I’m designing a PBIS Cell design for a customer (it allows assigning UID numbers, rather than generating per host like Samba or SSSD), I will try to design the customer to build Domain Local groups in the RESOURCE domain, and populate those groups into the Cell, with the membership coming from the USER domain.  This meets the AD design methodologies, means that the Unix team can be delegated rights to control the group membership in the RESOURCE domain themselves, but not have any rights to any user accounts in USER. This also means that any Active Directory auditing tools will pick up and audit the users properly, and when PBIS drops this “nice enablement”, the customers I have worked with won’t need to make changes to their environment.

Edit:
The information in this post came primarily from: https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/dd861330(v=ws.11)
and
https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc755692(v=ws.10)
When I originally wrote this in late 2017.

The UPS on the lab servers is near the end of its life, so we’ve changed the shutdown script in power outages to simply hard-power off some of the servers (using Rob’s fork of ESXIDown from https://github.com/docsmooth/esxidown ). Of course, the second DC had to be one of them, so that there would be enough battery left for the SQL server and FSMO / PDC to shut down cleanly. THis means that the second DC often fails to boot properly when the power comes back after our yearly ComEd outage.

So, how do you fix this without doing the research every time? Thankfully, modern versions of Windows can be configured to boot to recovery mode. If you log in and launch a command prompt, you can run the following commands to find and repair problems:

  1. Launch the command prompt.

    recovery mode cmd.exe window example

    Launching CMD.EXE in recovery window

  2. navigate to your drive with the NTDS.DIT file (on our lab server, it’s always d:\windows\ntds:
    d:
    cd\windows\ntds
  3. Run an ESENTUTL checksum on the Active Directory database file ntds.dit:
    d:\windows\system32\esentutl.exe /k ntds.dit

    ESENTUTL.exe completed checksum

    ESENTUTL.exe completed checksum

  4. Even though that’s successful, you’ll probably fail an integrity check:
    d:\windows\system32\esentutl.exe /g edb
    On our server, that always generates the error:

    The database is not up-to-date. Integrity check may find that this database is corrupt because data from the log files has yet to be placed in the database. It is strongly recommended the database is brought up-to-date before continuing! Do you wish to abort the operation?

  5. If the checksum passed and you get this error, try rebooting into Directory Services Repair Mode – exit the command prompt and hit “Restart” and then pound on F8 to get the DSRM boot option.
  6. If DSRM bluescreens, then you need to go deeper into esentutl.exe to repair your DB. If this is NOT your only DC, you will have data loss, but it should replicate from other DCs back into this one, so it shouldn’t be a huge problem.
    If DSRM works, try an ntdsutil in cmd.exe:
    ntdsutil.exe
    activate instance ntds
    files
    recover
  7. If ntdsutil file recovery errors with

    Could not initialize the Jet engine: Jet Error -543.
    Failed to open DIT for AD DS/LDS instance NTDS. Error -21478418113

    then you need to do more work with esentutl, but can continue inside DSRM, rather than having to reboot.

    If you couldn’t boot into DSRM, continue as below, but from the recovery install CMD.exe. I’ll continue these commands from THAT pathing, since it turns out not bothering to jump into DSRM makes for a faster recovery, with ensured data loss. I don’t care abuot data loss in our lab though.

  8. Try to recover the database: d:\windows\system32\esenutl.exe /ml d:\windows\ntds\edb
  9. If that doesn’t work, delete the edb.log files, then try recovery again. You’ll get an error like

    Operation terminated with error -501 (JET_errLogFileCorrupt, Log file is corrupt) after 2.123 Seconds.

    So backup your logs to a new location or delete them outright:
    mkdir log-backup
    move edb*.log log-backup
    move edb.chk log-backup

  10. Recreate the log files with a hard recovery of the database:
    d:\windows\system32\esentutl.exe /p d:\windows\ntds\ntds.dit
    You’ll get an error saying you should only run this on damaged or corrupt databases. The checks before this have proven that that is the case in this situation, so click “OK”.
  11. This should restore the database and complete successfully. Reboot and test it. If it doesn’t work, or doesn’t boot, try again in all offline mode without jumping to DSRM.
  12. If that still doesn’t work:
  13. Recheck the database integrity:
    cd \windows\ntds
    esentutl /g: ntds.dit
  14. Do a database repair again:d:\windows\system32\esentutl.exe /p ntds.dit
  15. And reboot when that completes successfully. You *should* now boot properly, and the edb.chk and edb.log files should get rebuilt.

So apparently it’s been 5 years since I last updated this series: https://www.totalnetsolutions.net/2012/12/09/lenovo-t430-running-kubuntu-12-10-for-extreme-battery-life/

i’ve restarted most of these configurations over the past 5 years, especially as I’ve switched away from WWAN to tethering, and from spinning rust to SSD, but a lot of the core concepts remain: about 6 years ago my battery died after 3.5 hours of VM troubleshooting, while on a flight, and I lost some data in the emergency “go to sleep, not hibernate”, which cost me 2 hours of rework in the hotel at midnight. My goal, now, is “be able to work multiple simultaneous tasks, have a VM running, and still get super-long battery life when I need it, but not impact performance noticeably.”

With powertop reporting <5W (14h remaining) power consumption while idle, and <6W (11 hours) with firefox open while I start to write this post in August, 2017, I think I’ve hit the mark reasonably well.

As with the Lenovo T430 in the previous post, everything I care about works right out of the box, but when I first started my custom kernels, I missed a few things that I had to add back in before writing this up.

Hardware


CPU: Intel(R) Core(TM) i5-6300U CPU @ 2.40GHz
Memory: 16GB RAM
VGA compatible controller: Intel Corporation HD Graphics 520 (rev 07)
Ethernet controller: Intel Corporation Ethernet Connection I219-LM (rev 21)
Network controller: Intel Corporation Wireless 8260 (rev 3a)

Audio device: Intel Corporation Sunrise Point-LP HD Audio (rev 21)
Bluetooth device: Intel (integrated on the USB)
Synaptics Touchpad and Twiddler Mouse

Jump to main sections with these links:
CPU Configuration
Network Configuration
Video Configuration
Encryption / Security configuration
Battery saving configuration
Custom kernel .config

CPU and Battery


I have a series of posts on my love of getting the most performance and battery life I can from my systems, see the last and first of the series for a bit more, or dig through my twitter on the subject. What’s new this year is the latest i5 Core CPU with Linux 4.4 has a new “pstate” performance governor that’s not actually buggy anymore, if you configure it right. I used to use the acpi_cpufreq governors “ondemand” on AC and “conservative” on battery. But the new pstate drivers apparently perform better (thanks Phoronix) AND scale down for battery savings better, so I needed to switch that. Since I was switching governors, I figured it was time to re-check my 2007 finding that moving from “GENERIC_CPU” to “MCORE2” saved me 30+ minutes alone.

Well, it does. But I didn’t keep the data, sorry. What this means is I once again needed to custom compile a kernel to get the right CPU options, and to get the new pstate driver. Since I was in doing that, and since the 2012 post, I’ve moved away from the default kernel Scheduler to Colin Kalvis’ BFS scheduler, so we get to patch THAT in as well. More on those options down at the custom kernel config section, but the point here is that BFS added some stability to heavy “running multiple VMs, and processing 4GB of raw data in Perl” swapping problems I was having, even with 16GB RAM, as well as not hurting my battery life, with a high possibility of 10-20 minutes extra life on normal operations.

The battery in the system is designed at 8157000 mWh, and after 6 months is down to 6621000 mWh. The “amount of time running” is based on the past 2 months, not day 1 of receiving the laptop.

Lastly, I’m still using cpufreqd, but the configuration is vastly simplified – pstate “powersave” when my AC is not plugged in, or the battery’s below 70%, and pstate “performance” otherwise. Ubuntu fixed the broken cpufreqd daemon sometime in 2014, so I’m back to the distribution default version of that, yay!

My custom cpufreqd.conf.

Network


I stopped using my jumbo frames script from here in Kubuntu 16.10, because apparently NetworkManager can figure that out on its own, and it’s been relatively successful. My wireless adapter connects to the new Netgear T6400 at near gigabit speed, but the R6400 doesn’t support jumbo frames itself, so I’m segmenting off some new VLANs to break the Jumbo Frames hosts from the wireless / nonintelligent hosts. That’ll mean resurrecting my jumbo frames script to instead set the VLAN Tag when I’m home.h

Sound


Sound has always been a joke for Linux users, but the Intel HD-Audio has been really solid for me for several years, especially with pulseaudio actually being relatively stable for me. When I recieved the laptop, I was having a problem where full-duplex audio was causing what appeared to be a storm of interrupts that hung the entire laptop. But about 2 months of debugging resulted in “I built a new kernel, and now it works fine.” I don’t know if it was a bug in the codec in the kernel, or something that silently patched. How I have Bluetooth audio headset, bluetooth headset for online conference calls, and appropriate switching for apps and reminders (reminders / alerts go to speakers and bluetooth in my config, in case I take the headphones off), with the options int he PulseAudio configuration in KDE. I have no “.asoundrc” or /etc/asound or /etc/pulse or ~/.pulse/client.conf anymore either, which is great!

Video


For the first time in years, I do not have a multi-graphics card system to deal with. The i915 driver works out of the box and is unremarkable, but functional. And great for battery life. But boring to discuss.

Encryption and Security

Encryption

During installation, I chose the option to use an encrypted LVM volume. This uses DM-Crypt to encrypt the full HDD, so that it has to be unlocked at boot time. The Kubuntu installer seems to forget this fact, so it also asks you to set up ecryptfs private home directories, which is NOT neccessary for a single-user laptop, since the whole OS is already encrypted. The only oddity with dm-crypt is that sometimes the splash screen prompt to unlock the computer doesn’t show. Originally, if I just wait for disk activity to disappear, and have a blank screen, I can just type the passphrase, and it’ll still unlock successfully. But I instead made a change to /etc/default/grub:


GRUB_CMDLINE_LINUX_DEFAULT="noquiet nosplash"

And now I don’t get the splash screen, and the prompt comes up properly right away. And I get all the hacker-y looking boot errors from systemd.

Security

Because this laptop has some sensitive work information on it, I wanted to get a bit more paranoid with the “unattended on a conference table” and “connected to a public wifi network” situations, especially since I actually have OpenSSH listening on all interfaces (yes, I ssh into my laptop from my phone more often than you do). I purchased a multi-protocol Yubikey and downloaded and installed the Yubikey PAM module for Challenge-Response, with the instructions on their website, here. Combined with Active Directory authentication, my cached user can only log in if the Yubikey is inserted into the laptop. So when I step away in meetings, the laptop locks, and my password can’t be cracked.

For additional security, I enrolled the root account on my laptop into my Password vault which rotates the root password every 14 days with a 50+-character random passcode, so even an attacker getting physical access once it’s booted (decrypted) will have little chance of breaking into the box even when I have the yubikey in place.

Additional Power Savings


I still run laptop-mode tools to cut down on power utilization from non-CPU peripherals. I could get more by having the ethernet port actually turn off when on battery, but I actually use it on battery quite a lot, so I’m not sure the hassle of re-enabling it is worth the battery savings. Here are the configurations I use:
intel-hda-powersave
intel-sata-powermgmt
intel_pstate
laptop-mode
runtime-pm
wireless-iwl-power
cpuhotplug
bluetooth
battery-level-polling
ethernet

What I’m now getting is 5-7W of power utilization while online with firefox and chrome both running, bluetooth running, and no VMs. Booting my Windows VM in VMware Workstation bumps me up to 15-20W, but I’m still getting 5 hours of battery life with no features disabled AND running a full Windows VM (the Windows VM has battery detection disabled, too). My non-VM battery life is reporting in the 9-11 hour range, but I’ve never had to use it that long to worry.

Kernel Config


I use the Ubuntu Kernel sources, mostly because the laptop tells me when there’s new Kernel sources with security fixes. I’m using BFS as my scheduler, which is fantastic when I get into “3 VMs using 12GB RAM and a reporting job wanting another 6GB” swap death. I have enough keyboard control to kill the reporting job, then shut down the VMs, and try the reporting job again. Before BFS, I either waited 6 hours, or rebooted the whole damn laptop.
BFS patches are here. If that doesn’t make sense, don’t use them. Please.
My custom kernel .config is here.

Building

The build system I use is the same as in 2012:

sudo apt-get install fakeroot build-dep linux-image-`uname -r`
sudo apt-get install linux-source
sudo usermod -a -G src YOUR_USERNAME

Now log out and back in, so that you’re a member of the “src” group.

cd /usr/src
sudo chown -R $USER:src .
tar -jxf ./linux-source-4.4.0/linux-source-4.4.0.tar.bz2
ln -s linux-source-4.4.0 linux
cd linux
wget http://www.totalnetsolutions.net/wp-content/uploads/2012/12/rob-config-20121204c.txt
mv rob-config-20121204c.txt .config
make oldconfig
make menuconfig

Make any changes you want in here, then exit and save

make-kpkg --initrd --rootcmd fakeroot --append-to-version=.20170912a kernel_image kernel_headers

You’ll get 2 DEB files in /usr/src that you can then install and boot to. the “append-to-version” I use as a dating system for my kernels. “20170912a” means the 2nd kernel attempt on September 12, 2017, the day I’m writing this post (first attempts get no letter).

Sometimes it’s nice to know what’s happening under the hood, so let’s talk about how Group Policy is built, by tearing down how to access a particular policy. First, Group Policy is implemented in 2 parts, an LDAP part and a file part, delivered via SMB (CIFS if you’re oldschool) via DFS (Distributed FIle SYstem). Because the DFS part is replicated completely differently than the AD part, there’s a version number for each Group Policy object that’s stored in both places to keep them in sync. Most GPO engines remember the last version they applied by remembering the lowest of the 2 numbers (the LDAP version and the file version in the GPT.INI), if they don’t match.

Let’s talk about the “Default Domain Policy” which everyone will have one of. To find where that policy lives, you have to ask AD. The policy doesn’t actually live in the OU or Domain where it’s linked, so we have to back out the link:
ldap_search_s(ld, "dc=company,dc=com", 2, "(objectClass=organizationalUnit)", gpLink, base, &msg)
We’ll get back something like:

gPLink: [LDAP://CN={6AC1786C-016F-11D2-945F-00C04fB984F9},CN=Policies,CN=System,DC=company,Dc=com;0]

Now, this is a multi-valued array, because multiple GPOs can be linked, in order, to a single OU or Domain or Site. But we only care about this one, so let’s see what’s in it:

ldap_search_s(ld, "CN={6AC1786C-016F-11D2-945F-00C04fB984F9},CN=Policies,CN=System,DC=company,DC=com", 2, "(objectClass=*)", gPCMachineExtensionNames;gPCFileSysPath;displayName;versionNumber, 0, &msg)

That’ll get us the Client Side Extensions (where the work actually happens), and what the file path to the files in the estension are stored, as well as the pretty name of the Group Policy Object:

displayName: Default Domain Policy;
gPCFileSysPath: \\child1.lwtest.corp\sysvol\child1.lwtest.corp\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9};
gPCMachineExtensionNames: [{35378EAC-683F-11D2-A89A-00C04FBBCFA2}{53D6AB1B-2488-11D1-A28C-00C04FB94F17}{53D6AB1D-2488-11D1-A28C-00C04FB94F17}{D02B1F72-3407-48AE-BA88-E8213C6761F1}][{827D319E-6EAC-11D2-A4EA-00C04F79F83A}{803E14A0-B4FB-11D0-A0D0-00A0C90F574B}][{B1BE8D72-6EAC-11D2-A4EA-00C04F79F83A}{53D6AB1B-2488-11D1-A28C-00C04FB94F17}];
versionNumber: 15;

So we have the Default Domain Policy, as desired, but there are a bunch of client side extensions here. It’d be nice to know what they all do generically, without having to inspect each one.
And TechNet delivers on that desire: a list of all Client Side Extensions (in 2010) by GUID for easy reference. Now, I’m writing this, because someone asked where the Password Policy for the domain was stored. Well, that appears to be in: {827D319E-6EAC-11D2-A4EA-00C04F79F83A} Security, which our Default Domain policy applies. So, let’s go find the data!

One of the attributes in the list we last requested was gPCFileSysPath which returned a normal SMB share. If you browse to that share, you’ll see 3 objects:

  • A folder named “MACHINE”
  • A folder named “USER”
  • a file named “GPT.INI”

The GPT.INI will only have 2 lines:

[General]
Version=15

That’s the version number, that you can compare to the “versionNumber” property from the object. If they’re the same, you’re good. If not, your AD isn’t in sync.

In the “MACHINE” Folder are all the Computer Policy settings, and in the “User” folder are all the User Policy settings. Since we were talking about the Password Policy, which is affected on the SAM on the server, it’s a MACHINE setting. If you were to poke through, eventually you’d find this file:

\\domain\sysvol\domain\\MACHINE\Microsoft\Windows NT\SecEdit\GptTmpl.inf

with this data:

[Registry Settings]
MACHINE\System\CurrentControlSet\Services\Netlogon\Parameters\MaximumPasswordAge=4,15

And there’s your password policy, via LDAP and SMB only.

For a bit of additional background, when a computer processes this data, in this order, it will actually only apply CSEs from the gPCMachineExtensionNames that the computer recognizes and has DLLs (or whatever code, if it’s non-Microsoft vendor CSE) that can apply the CSE. This makes it technically safe to put multiple GPOs for multiple Operating sytsems on the same OU structure, knowing that the client computer won’t even bother downloading the files for un-recognized CSEs.

Now, that’s a lot of stuff to type into ldp.exe, how can we make a report on this a bit easier? Well, PowerShell could do it, but one of the products I work on is PowerBroker Open https://github.com/BeyondTrust/pbis-open and https://www.beyondtrust.com/products/powerbroker-identity-services-open/ which includes a CLI for browing ldap called “adtool”. With a bit of bash, we can list out all the group policy objects by name attached to a single OU:

$ cat report-gpos-by-ou.sh
GP=`adtool -a lookup-object --dn "$@" --attr gPLink`;
GPO=`echo $GP | sed -e 's/\[LDAP:\/\///g' -e 's/;[[:digit:]]\]/ /g'`
if [ -n "$GPO" ]; then
echo "";
echo "$OU";
for P in $GPO; do
G=`adtool -a lookup-object --dn "$P" --attr displayName`;
grep -q "$G" /tmp/gpos.txt;
if [ $? -ne 0 ]; then
echo $G >> /tmp/gpos.txt;
fi;
echo "$G";
done;
fi;
$ ./report-gpos-by-ou.sh "OU=Company,DC=domain,DC=com"
OU=Company,DC=domain,DC=com
PBUL Basics
GP-Preferences
$

Next Page »