?
Solved

Get File Owner of a UNC file when run on a Windows 2000 Server

Posted on 2005-03-15
2
Medium Priority
?
703 Views
Last Modified: 2012-06-21
I have the need to be able to retrieve the file owner from a host of files that live throughout our network.  We are provided the UNC names and need to return the file owner.  I can get this working on my workstation, although its very slow, using a mapped drive but not with a unc name.  As a last resort the mapped drive is OK.  The problem is that I need to run this from a server (windows 2000 Server) and that even using a mapped drive, no owner is returned.  

Question is 1) How can I get the file owner from a unc filename, and 2) how can I get it to run on the server?

The code is:

imports system.management

    Public Function GetFileOwner(ByVal strFile As String) As String
        Dim oManagementObject As New ManagementObject("Win32_LogicalFileSecuritySetting.path='" & strFile & "'")
        Dim oManagementBaseObject As ManagementBaseObject
        'oManagementObject.Path = ""
        Dim oDescriptor As ManagementBaseObject
        Dim oOwner As ManagementBaseObject
        Dim Owner As PropertyDataCollection
        Dim strOwner As String
        Try
            'Get the security descriptor for this object
            oManagementBaseObject = oManagementObject.InvokeMethod("GetSecurityDescriptor", Nothing, Nothing)
            oDescriptor = oManagementBaseObject.Properties("Descriptor").Value()
            'Get the Ownerobject
            oOwner = oDescriptor.Properties("Owner").Value
            'Read the Properties to a Propertydatacollection Object
            Owner = oOwner.Properties
            strOwner = Owner("Name").Value
        Catch e As Exception
            MsgBox(e.Message)
            ' Problem getting information
            strOwner = ""
        End Try
        Return (strOwner)
    End Function
0
Comment
Question by:vbtl
2 Comments
 
LVL 41

Accepted Solution

by:
graye earned 2000 total points
ID: 13562014
I'd consider using the APIs....   Here is an example that works for both local and UNC paths

Imports System.Runtime.InteropServices

Module FileOwner

    Private Declare Function GetFileSecurity Lib "advapi32.dll" Alias "GetFileSecurityA" ( _
    ByVal lpFileName As String, ByVal RequestedInformation As Integer, _
    ByRef pSecurityDescriptor As Byte, ByVal nLength As Integer, ByRef lpnLengthNeeded _
    As Integer) As Integer

    Private Declare Function GetSecurityDescriptorOwner Lib "advapi32.dll" (ByRef _
    pSecurityDescriptor As Byte, ByRef pOwner As Integer, ByRef lpbOwnerDefaulted As _
    Integer) As Integer

    Private Declare Function LookupAccountSid Lib "advapi32.dll" Alias "LookupAccountSidA" ( _
    ByVal lpSystemName As String, ByVal Sid As Integer, ByVal name As String, _
    ByRef cbName As Integer, ByVal ReferencedDomainName As String, ByRef _
    cbReferencedDomainName As Integer, ByRef peUse As Integer) As Integer

    <DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
    Function ConvertSidToStringSid( _
    ByVal psid As IntPtr, _
    ByRef ssp As IntPtr) As Boolean
    End Function


    Private Const OWNER_SECURITY_INFORMATION = &H1
    Private Const SD_SIZE = 48
    Private Const NAME_SIZE = 64

    Function GetFileOwner(ByVal szfilename As String) As String
        Dim bSuccess As Integer     ' Status variable
        Dim sizeSD As Integer       ' Buffer size to store Owner's SID
        Dim pOwner As Integer       ' Pointer to the Owner's SID
        Dim name As String          ' Name of the file owner
        Dim domain_name As String   ' Name of the first domain for the owner
        Dim name_len As Integer     ' Required length for the owner name
        Dim domain_len As Integer   ' Required length for the domain name
        Dim sdBuf() As Byte         ' Buffer for Security Descriptor
        Dim nLength As Integer      ' Length of the Windows Directory
        Dim deUse As Integer        ' Pointer to a SID_NAME_USE indicating type of account
        Dim sid_ptr, sidstring_ptr As IntPtr
        Dim SidString, MachineName As String
        Dim LastError As Integer

        sizeSD = SD_SIZE
        ReDim sdBuf(sizeSD - 1)

        bSuccess = GetFileSecurity(szfilename, OWNER_SECURITY_INFORMATION, sdBuf(0), sizeSD, sizeSD)
        If (bSuccess = 0) Then
            Debug.WriteLine("File=" & szfilename & ", GetFileSecurity=" & Err.LastDllError)
            Return "Error"
        End If

        bSuccess = GetSecurityDescriptorOwner(sdBuf(0), pOwner, 0)
        If (bSuccess = 0) Then
            Debug.WriteLine("File=" & szfilename & ", GetSecurityDescriptorOwner=" & Err.LastDllError)
            Return "Error"
        End If

        ' we often need a bit of breathing room between these two API calls
        Application.DoEvents()

        ' are we doing this remotely? (detected source of mapped drive letters?)
        If szfilename.StartsWith("\\") Then
            MachineName = szfilename.Split("\")(2)
        Else
            MachineName = ""
        End If

        name_len = NAME_SIZE
        domain_len = NAME_SIZE
        name = Space(name_len)
        domain_name = Space(domain_len)
        bSuccess = LookupAccountSid(MachineName, pOwner, name, name_len, domain_name, domain_len, deUse)
        If (bSuccess = 0) Then
            LastError = Marshal.GetLastWin32Error()
            ' if we fail on error 1332, then use the SID in the name
            If LastError <> 1332 Then
                Debug.WriteLine("File=" & szfilename & ", LookupAccountSid= " & LastError.ToString)
                Return "Error"
            Else
                sid_ptr = New IntPtr(pOwner)
                If ConvertSidToStringSid(sid_ptr, sidstring_ptr) = False Then
                    LastError = Marshal.GetLastWin32Error()
                    Debug.WriteLine("File=" & szfilename & ", ConvertSidToStringSid= " & LastError.ToString)
                    Return "Error"
                Else
                    SidString = Marshal.PtrToStringAuto(sidstring_ptr)
                    Marshal.FreeHGlobal(sidstring_ptr)
                    domain_len = 0
                    name = SidString
                    name_len = Len(name)
                End If
            End If
        End If

        If domain_len > 0 Then
            Return Left(domain_name, domain_len) & "\" & Left(name, name_len)
        Else
            Return Left(name, name_len)
        End If
    End Function

End Module
0
 

Author Comment

by:vbtl
ID: 13600017
Like it!  Thanks
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: Kraeven
Introduction Remote Share is a simple remote sharing tool, enabling you to see, add and remove remote or local shares. The application is written in VB.NET targeting the .NET framework 2.0. The source code and the compiled programs have been in…
If you're writing a .NET application to connect to an Access .mdb database and use pre-existing queries that require parameters, you've come to the right place! Let's say the pre-existing query(qryCust) in Access takes a Date as a parameter and l…
Exchange organizations may use the Journaling Agent of the Transport Service to archive messages going through Exchange. However, if the Transport Service is integrated with some email content management application (such as an anti-spam), the admin…
The Relationships Diagram is a good way to get an overall view of what a database is keeping track of. It is also where relationships are defined. A relationship specifies how two tables connect to each other. As you build tables in Microsoft Ac…
Suggested Courses
Course of the Month12 days, 21 hours left to enroll

579 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question