Wednesday, December 17, 2014

Regarding the Long Path

I shared my post regarding the Windows long path dilema on the /r/sysadmin subreddit and on G and quite honestly there was quite a reaction. Thank you everyone who took the time to read my article, and I wanted to share something that /u/elkBBQ shared



Source: http://www.xkcd.com/1459/

I had a good chuckle, but on a more serious note. I learned quite a few things from the /r/sysadmin community but I did want to clarify for those who still believe that this is a limitation in the file system (NTFS), but let me tell you it is not. NTFS actually handles up to 32k characters on paths; however, Windows is not able to use it because of a limitation in its API, and while there is some ways to force it like using Unicode and other ways to get around the issue (see link below) there is no office or really a 'good' solution.

I wanted to share the following Article that explains a lot on this issue. The article is written by Kim Hamilton of the BCL Team and as (s)he explains in an answer to a comment:

Diego,
We do need a solution in the underlying windows API, but this would most likely emerge as new APIs rather than changing the existing ones. We've discussed this at length on the longpath alias at Microsoft (yes, we have a whole alias devoted to the issue!) and there are no plans to change the existing ones, since it would break third party code that depend on MAX_PATH buffers on the stack.
We've discussed migration plans to enable those existing Win32 APIs not to enforce MAX_PATH but there are no clear solutions; this would need to be done very carefully to avoid breaking existing Windows-based apps.
The main reason I think we need new Win32 APIs is that \\?\ lumps together long paths and non-canonical paths, so you have to do tricks to get canonicalization on \\?\ paths. That sort of work shouldn't be pushed onto the callers just to achieve long paths.
Thanks,
Kim

Date: 13 Feb 2007 7:08 PM

Sadly in 2007 Microsoft believed this was an issue, and their team were working on a solution. It has been 7 years  and the issue still persists, and from what we know off there is no soon to come fix.

Kind regards to everyone,
Me.

PS. Below I'll post some of the most common work arounds for this issue:

Force Unicode: \\?\PATHHERE (please see the link above for details on how to use this method)
Con: Not widely supported

Map a drive or use subst to map a drive.
Con: Unfortunately the only way to get this to work would be to know the exact path. You'll have to map the drive to a subfolder that is close to the one that breaks the limit. Also doesn't play very well with scripting.

Someone (and I apologize I cannot find the user who posted this on the reddit post)  recommended to use VBScript; however, I do not posses this skill, so if someone could show us a way for this that'd be awesome!

Peter Kriegel pointed me to a PowerShell Module called  File System Security PowerShell Module 3.2.2 but I'm not familiar with it and haven't had a chance to look deep into it as to try to find out who they manage to make it work. Again if someone has some information that they can provide regarding the inner workings, or if indeed truly works I'd appreciate the information. 

Tuesday, December 16, 2014

Permissions

So I worked on this script for a few hours yesterday

$drive = "F:\"
$fileName = "C:\Audits\FDrive_Audit_$((Get-Date -Format d).Replace(" ","_").replace("/","-").Replace(":",'-')).csv"
$ACL_Report = @()
$Stack = New-Object System.Collections.Stack

function getPermissions($folder)
{
    $ACL_Report = @()
    foreach($reference in (Get-ACL $folder | %{$_.Access}))
    {
        $aclObj = New-Object psobject
        $aclObj | Add-Member -MemberType NoteProperty -Name 'Path' -Value $folder
        $aclObj | Add-Member -MemberType NoteProperty -Name 'Account' -Value $reference.IdentityReference
        $aclObj | Add-Member -MemberType NoteProperty -Name 'Access' -Value $reference.FileSystemRights
        $aclObj | Add-Member -MemberType NoteProperty -Name 'Inherited' -Value $reference.IsInherited
        $aclObj | Add-Member -MemberType NoteProperty -Name 'Inheritance' -Value $reference.InheritanceFlags
        $aclObj | Add-Member -MemberType NoteProperty -Name 'Propagation' -Value $reference.PropagationFlags
        $ACL_Report += $aclObj
    }
    $ACL_Report += " "
    $ACL_Report | Export-Csv $fileName -NoTypeInformation -Append
}

function create-Queue($currentFolder)
{
    foreach($folder in (Get-ChildItem $currentFolder -Directory))
    {
        getPermissions $folder.FullName
        $Stack.Push($folder.FullName)
        create-Queue $stack.Pop()
    }
}
create-Queue $drive

The script is intended to go through every path in a directory and get all of the permissions of the folders, and export them into a CSV. Surprisingly enough, the script itself works great too; however, i came to the sad problem of paths being too long and not getting all of the permissions. I've looked at this from a long of angles and feel like I've ran out of Google power here. If someone has an idea of how to get this done, that doesn't include running a Robocopy first to get the paths. Please share with me. Kind regards, Me.

Path is too long

I believe that I should let everyone know that once again Microsoft has not fixed the path is too long issue in his newest release Windows X.



I been deal with this atrocious issue every now and then when writing scripts that run against our file servers, and I must say its a real pain in the rear. I pray one day this will be fixed.

Good day to all.

Edit 9/16/2015: I'm not sure why the pictures are gone. I'll try to replicate the issue once again and repost them soon.

Edit 1/16/2016: I finally took the time to recreate the error and re-upload the picture.

Thursday, December 4, 2014

Don't learn many, become an expert at one!

Today I was reading this article. It was talking about the main differences between PHP and .NET what one should learn, and let me tell you something I wish I had read it back when I was younger. 

I took Programming I and II in High School and then again in College, but unfortunately I don't think I ever learned much. Yeah I learned syntax and learned some of the logic behind programming, but nobody ever told me what was said in this article:
"There are benefits to learning either PHP or .NET. Should you learn both? If you’re new to programming, the answer, I think, is No: At an early stage in your career, you need to focus your energy on getting very good at one thing, which will translate into higher-paying jobs down the road. If you try to go to broad, you will stretch yourself thin and not master anything. (I made that mistake early in my career, and it started hurting my job prospects—employers tend to distrust resumes that list hundreds of technologies in which the applicant is supposedly an expert.) Pick one thing and be great at it!" - Jeff Coswell

In this quote he specifies something very important that I wish to pass to anyone starting with programming: Don't learn multiple languages, learn one and become an expert at it, then switch to other ones if you want to. I wish very much wish someone had told me this, but because nobody did, I ran around through most of my amateur days learning Ruby, Java, C++, C#, Python, Perl, even looked at Haskell and learned a lot of the syntax but in reality I learned nothing because I was never an expert with any of them.

I felt strongly that this needed to be shared because I don't think its quite common knowledge. For example, in college Programming I was Introduction to Java, Programming II was introduction to C++, and Programming III was cancelled due to not having enough students sign up, but I believe it was introduction to C#. 

So hear my advice: If you enjoy programming and would like to pursue a career in this field, you need to pick a language, and preferably once that is common enough that you can make a living with, and become an expert. If you then decide you would like to try something else then your transition will be much easier. 

If not you'll probably end up like me learning a lot of syntax and not knowing much.

Good luck if you are starting, and if you are an experience developer please let me know what you think, or if you also went through something like this in your earlier days. 

Friday, November 14, 2014

PowerShell and Scheduled Tasks

I have been setting up some schedule PowerShell scripts through the Task Scheduler; however, I was having a bit of trouble with one of the scripts. 

The script would run perfectly if I ran it manually, but when I ran the task nothing would happen. As you might know this is a bit of a problem because schedule tasks don't not show the console, and won't allow you to see the errors. The Task's log are not very helpful either.

What helped me troubleshoot the problem is this little cmdlet:

Start-transcript -path C:\Temp\Filename.txt

Placing that command at the beginning of your script will create a transcript file. The transcript file will contain everything that would print into the console, and it should look a little like this:


-------------------------------------------------------------

**********************
Windows PowerShell transcript start
Start time: 20141114101902
Username  : DOMAIN\S.AD.Util 
Machine  : HOSTNAME (Microsoft Windows NT 6.3.9600.0) 
**********************
Transcript started, output file is C:\Temp\Transcript_11-14-2014.txt

ModuleType Version    Name                        ExportedCommands     
---------- -------    ----                        ----------------     
Script     1.0        tmp_scev4zye.pet          {Get-DServerSetti...

-------------------------------------------------------------

If there is any errors they will show here, even if they are not stopping errors. Which is great because at one point my script was sending the email and successfully completing, but failing to create the report all together and sending a blank email.

I hope this might help someone out there! 

Wednesday, November 12, 2014

Update: Locked accounts

This post is related to a previous post.

We have recently been receiving several incidents regarding accounts that are getting locked out. Our Service Desk and Desktop team have been unable to find the cause and so they escalated to us. Following the log trail we have found that this devices are normally getting locked out in our CAS server. This was easy enough to be determined by using a Microsoft tool called Lockoutstatus; however, we had been unable to determine exactly what was causing them to get locked out in the CAS server and we would simply inform the user that their account was getting locked out by a smart device using ActiveSync. 

I recently found in this article though that there is a way to figure out what the device exactly is causing the issue by looking at the IIS logs in the CAS Server. The article explains in detail what the log looks like, and what each field means. 

I'll try to provide a bit of a summary, but please visit the full article for more details. 

The logs can be found in the following locations:


  • In Windows Server 2003: C:\WINDOWS\system32\LogFiles
  • In Windows Server 2008: C:\inetpub\logs\LogFiles\W3SVC1
  • In Windows Server 2012: I believe it should be the same but since we don't have a CAS server on a 2012 machine I wasn't able to confirm.

Here is the example provided, and I'll try to break it down as I understood it:

2012-01-10 14:42:26 172.32.22.12 POST /Microsoft-Server-ActiveSync/default.eas User=ratishnair&DeviceId=Appl8xxxxx4S&DeviceType=iPhone&Cmd=FolderSync&Log=PrxFrom:10.123.33.88_Error:BackingOffMailboxServer_ 443 CONTOSO\CAS01$ 10.123.33.88Apple-iPhone3C1/901.405 503 0 0 765


  • 172.32.22.12 : The IP address of where the command was sent to.
  • POST : The type of command that was issued on the Log.
  • /Microsoft-Server-ACtiveSync/ : States that the type of command is ActiveSync.
  • Default.eas : States the ActiveSync policy - this might vary depending on your settings.
  • User= : The username who is running the command.
  • DeviceID= : The ID that was assigned to the ActiveSync Device by the Exchange server when it was first setup. 
  • DeviceType= : The Device Model - We've been using this to point the users to their device having issues.
  • Apple-Iphone3C1/901.405 : The device's firmware version.
  • 503 : This is the error code, which can be any of the ones found below:
    • 200 – Authentication pass
    • 400 – Bad/invalid request
    • 401 and 403 – Unauthorized/server refusing request
    • 404  – File not found
    • 449 – Retry
    • 500 – Server error
    • 503 – Service unavailable
  • 0 0 765 : I'm not 100% sure what this part means; however, the last 3 digits appear to change from log to log. I'm doing further research on this.
Well I hope this might help you troubleshoot this type of issues! I know it will help us a lot, and I am even thinking about allowing the Service Desk read access to this logs, though our Exchange admins aren't too fond of the idea, yet. 

Windows Server 2003 You did it again!

We recently had an outage on some of our VMWare hosts and after the outage was resolved and the hosts came back online we brought up all the VMs back online. Later that day one of my co-workers received a call regarding one of the VMs that was not able to be accessed.

After thoroughly troubleshooting the issue he asked me for some input.


He had done everything anyone would do to troubleshoot an issue with a VM Network:



  • Made sure the IP address and subnet were correct.
  • He double checked the VLAN on the VM host. 
  • He deleted the virtual NIC and added a new one with a different driver
Unfortunately nothing was working. I took over the issue, and I was honestly at a stomp. After redoing everything he had done and a few other things I finally decided to check the Windows EventLog - I probably should have done that sooner. I found an event that said the following:

Event Type: Error

Event Source: IPSEC
Event Category: None
Event ID: 4292
Date:
Time: 
User: N/A
Computer: COMPUTER_NAME
Description:
The IPSec driver has entered Block mode. IPSec will discard all inbound and outbound TCP/IP network traffic that is not permitted by boot-time IPSec Policy exemptions.

After some researching I found the following VMWare article. It turns out this is actually not that an uncommon occurrence on VMs running Windows Server 2003. 

I followed the given instructions and I disabled the IPSec service - even though it wasn't even running - and rebooted the VM. When the system came back online so was the network. 

I hope this might help someone out there! 

Tuesday, August 19, 2014

Web Platform

So for the past few weeks I have put on my learning hat and been learning the ways of the website development. This of course was no easy task, but after many headbangs against my desk I feel like I'm finally making some progress. I was finally able to create a Master page using VS Express 2013 for Web. I got a HTML5/CSS3 Template going, and I believe I can finally start creating pages, backed by C#. 

This is all still a huge learning curve but I gotta say I feel more confident now. So far the resources that I've used to learn this is training on cbtnuggets, I've also used this link here to get a better understanding of CSS http://learnlayout.com/position.html. 

So far what I been learning is very well documenting so I haven't really posted anything, but once I start dabbling into deeper issues I'll try to post some cool stuff. 

Tuesday, August 5, 2014

Stand-alone Application to Web Application

My learning c# project that I had been working is being changed. One of the Architects saw what I had and really liked it and wants me to transform it into a web portal instead of a stand alone application. I agree to this changed, but now I have to learn HTML/CSS/JavaScript and i feel like I'm back on step one.

I hope to get some good knowledge out of this though and I'll keep posting when I find cool things.

Wednesday, July 23, 2014

C# Learning - Creating new AD accounts

I've been coding in PowerShell for 2 years now, and I gotta say switching over to C# is a nightmare! I do like it though, its has been a great fun experience. Once I got past the whole "Hello world" tutorials and learning the syntax it got a lot more fun. I'm not that I'm an expert in any way, but I believe I'm starting to get a hang of what is going on, which makes me happy.

Today as part of my on going project I had to create a function to create AD users through C#, and I'm using System.DirectoryServices class which actually requires that you add each property to the user, but doesn't actually tell you what does properties are, so after some looking around I found a table in this article. It made it a lot simpler than trying to guess the names. Here is the table for those that just want to get a quick look:


LDAP Attribute

Example

CCountry: e.g GB for Great Britain.
CN - Common NameCN=Guy Thomas.  Actually, this LDAP attribute can be made up from givenName joined to SN.
CNMaps to 'Name' in the LDAP provider. Remember CN is a mandatory property.  See also sAMAccountName.
descriptionWhat you see in Active Directory Users and Computers.  Not to be confused with displayName on the Users property sheet.
displayNamedisplayName = Guy Thomas.  If you script this property, be sure you understand which field you are configuring.  DisplayName can be confused with CN or description.

DN - also distinguishedNameDN is simply the most important LDAP attribute.
CN=Jay Jamieson, OU= Newport,DC=cp,DC=com
givenNameFirstname also called Christian name
homeDriveHome Folder : connect.  Tricky to configure
initialsUseful in some cultures.
namename = Guy Thomas.  Exactly the same as CN.
objectCategoryDefines the Active Directory Schema category. For example, objectCategory = Person
objectClassobjectClass = User.  Also used for Computer, organizationalUnit, even container.  Important top level container.
physicalDeliveryOfficeNameOffice! on the user's General property sheet
postOfficeBoxP.O. box.
profilePathRoaming profile path: connect.  Trick to set up
sAMAccountNameThis is a mandatory property, sAMAccountName = guyt.  The old NT 4.0 logon name, must be unique in the domain. 
sAMAccountNameIf you are using an LDAP provider 'Name' automatically maps to sAMAcountName and CN. The default value is same as CN, but can be given a different value.
SNSN = Thomas. This would be referred to as last name or surname.
titleJob title.  For example Manager.
userAccountControlUsed to disable an account.  A value of 514 disables the account, while 512 makes the account ready for logon.
userPrincipalNameuserPrincipalName = guyt@CP.com  Often abbreviated to UPN, and looks like an email address.  Very useful for logging on especially in a large Forest.  Note UPN must be unique in the forest.
wWWHomePageUser's home page.

Examples of Exchange Specific LDAP attributes

homeMDB Here is where you set the MailStore
legacyExchangeDNLegacy distinguished name for creating Contacts. In the following example,
Guy Thomas is a Contact in the first administrative group of GUYDOMAIN: /o=GUYDOMAIN/ou=first administrative group/cn=Recipients/cn=Guy Thomas
mailAn easy, but important attribute.  A simple SMTP address is all that is required billyn@ourdom.com
mAPIRecipient - FALSEIndicates that a contact is not a domain user.
mailNicknameNormally this is the same value as the sAMAccountName, but could be different if you wished.  Needed for mail enabled contacts.
mDBUseDefaultsAnother straightforward field, just the value to:True
msExchHomeServerNameExchange needs to know which server to deliver the mail.  Example:
/o=YourOrg/ou=First Administrative Group/cn=Configuration/cn=Servers/cn=MailSrv
proxyAddressesAs the name 'proxy' suggests, it is possible for one recipient to have more than one email address.  Note the plural spelling of proxyAddresses.
 targetAddressSMTP:@ e-mail address.  Note that SMTP is case sensitive.  All capitals means the default address.
 showInAddressBookDisplays the contact in the Global Address List.

cCountry or Region
companyCompany or organization name
departmentUseful category to fill in and use for filtering
homephoneHome Phone number, (Lots more phone LDAPs)
l  (Lower case L)L = Location.  City ( Maybe Office
locationImportant, particularly for printers and computers.
managerBoss, manager
mobileMobile Phone number
ObjectClassUsually, User, or Computer
OUOrganizational unit.  See also DN
pwdLastSetForce users to change their passwords at next logon
postalCodeZip or post code
stState, Province or County
streetAddressFirst line of address
telephoneNumberOffice Phone
userAccountControlEnable (512) / disable account (514)

Examples of Obscure LDAP Attributes

dNSHostname
rID
url
uSNCreated, uSNChanged

I removed the Ads because I'm not sure if they would affect his stuff. 

Here is the difference in code from creating users in PowerShell and in C#:

PowerShell * In this particular example I'm taking the values from a CSV, which allows me to create multiple accounts very quickly. 

//This is needed
Import-Module ActiveDirectory

New-ADUser -AccountPassword (ConvertTo-SecureString -AsPlainText "PASSWORDHERE" -Force-Server 'DCHOSTNAME' `
        -Enabled $true `
        -Name $file.username `
        -GivenName $file.name `
        -Surname $file.lastname `
        -Initials $file.middle `
        -DisplayName $file.displayname `
        -SamAccountName $file.username `
        -Office $file.office `
        -Department $file.Department `
        -Company $file.company `
        -StreetAddress $file.Street `
        -City $file.city `
        -State $file.state `
        -PostalCode $file.postalcode `
        -Country $file.country  `
        -Description $file.description `
        -Path $file.path `
        -UserPrincipalName $file.userprincipalname `
        -EmailAddress $file.userprincipalname `
        -OtherAttributes @{'co'="United States"'countryCode'="840"


C# * Please note that I am passing the variables from the "OnClick" function for a button, and also that all the properties name are not provided to you as they are in PowerShell. Final note there is some parameters that have not yet been used as they will be added at a later point when I create the mailbox. 

//These are required
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;

public void createUser(int ticketnumber, string firstname, string middleIn, string lastName, 
string samaccountname, string email, string telephone, string hemisphere, string company, 
string office, string address, string city, string state, string division, string Code, 
string OrganizationalUnit, string country, string department, string title, string displayName, 
string postalCode, string co, string Manager)
        {
            string path = "LDAP://" + OrganizationalUnit;
            int NORMAL_ACCOUNT = 0x200;
            int PWD_NOTREQD = 0x20;
            try
            {
                using (DirectoryEntry ou = new DirectoryEntry(path))
                {
                    DirectoryEntry user = ou.Children.Add("CN=" + samaccountname, "user");
                    user.Properties["SamAccountName"].Add(samaccountname);
                    user.Properties["userPrincipalName"].Add(samaccountname + "@DOMAIN");
                    user.Properties["name"].Add(firstname + " " + lastName);
                    user.Properties["givenName"].Add(firstname);
                    user.Properties["initials"].Add(middleIn);
                    user.Properties["SN"].Add(lastName);
                    user.Properties["telephoneNumber"].Add(telephone);
                    user.Properties["company"].Add(company);
                    user.Properties["physicalDeliveryOfficeName"].Add(office);
                    user.Properties["streetAddress"].Add(address);
                    user.Properties["l"].Add(city);
                    user.Properties["st"].Add(state);
                    user.Properties["co"].Add(country);
                    user.Properties["C"].Add(co);
                    user.Properties["department"].Add(department);
                    user.Properties["title"].Add(title);
                    user.Properties["userAccountControl"].Value = NORMAL_ACCOUNT | PWD_NOTREQD;
                    user.Properties["description"].Add("AC #" + ticketnumber + " JB | Created with JBSoftware");
                    user.Properties["displayName"].Add(displayName);
                    user.Properties["objectCategory"].Add("PERSON");
                    user.Properties["postalCode"].Add(postalCode);
                    user.Properties["manager"].Add(Manager);
                    user.CommitChanges();
                }
            }
            catch (System.DirectoryServices.DirectoryServicesCOMException E)
            {
                MessageBox.Show(E, "ERROR!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                throw;
            }        }


Well I think that is it for the day, I hope that this information might be useful to someone out there!

Edit >
It seems that I forgot a simple o in the Country property. (see in bold)