QuickTip: Use WMI to determine remote users accessing files and shares

A question popped up on the PowerShell.com forums, asking if it was possible to view a list of users accessing network shares on a system. It turns out this is a relatively easy task using WMI

Get-WmiObject -Class Win32_ServerConnection -ComputerName server01

Now this does output a large amount of data, so I would recommend filtering some of the more useful properties for example:

Get-WmiObject -Class Win32_ServerConnection -ComputerName server01 |
Select-Object -Property ComputerName,ConnectionID,UserName,ShareName

Of course it is also possible to query for this information using the newer Get-CimInstance cmdlet:

Get-CimInstance -Class Win32_ServerConnection -ComputerName server01

There you have it, accessing the full list of users from a local or remote system that are accessing shared folders on the system is quite easily done when using PowerShell.

QuickTip: Convert .csv to .xlsx using Excel.Application

Using the Excel.Application Com-object converting a csv file to an xlsx file is quite simple, it can be written up in a single one-liner:

((New-Object -ComObject "Excel.Application").workbooks.open('c:\list.csv')).SaveAs('c:\list.xlsx',51)

Now this does leave an Excel process open so if you would like the process to be closed afterwards we could amend the code as follows:

$CurrentExcel = Get-Process Excel | Select-Object -ExpandProperty ID
((New-Object -ComObject "Excel.Application").workbooks.open('c:\list.csv')).SaveAs('c:\list.xlsx',51)
Start-Sleep 1
Get-Process Excel | Where-Object {$CurrentExcel -notcontains $_.ID} | Stop-Process -Force

By first gathering the list of all open Excel processes we can make sure that any previously opened Excel processes are not accidentally closed. That leaves us with a quick and easy piece of code to convert comma separated files to xlsx files on the fly.

For more information about the Excel.Application object have a look at its MSDN entry:
Application Object Excel

Active Directory Friday: Determine tombstone lifetime

In Active Directory objects are tomb stoned after a deletion occurs. This is allow replication to occur between domain controllers before an object is deleted from the Active Directory data store. The default value depends on the server when the forest was initially created, Microsoft recommends that this is set at 180 days.

The tombstone lifetime is set at the forest level and can be viewed by running the following code:

([adsi]"LDAP://CN=Directory Service,CN=Windows NT,CN=Services,$(([adsi](“LDAP://RootDSE”)).configurationNamingContext)").tombstoneLifetime

Alternatively this can also be retrieved by using the Get-ADObject cmdlet:

$HashSplat = @{
    Identity = 'CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=jaapbrasser,DC=com'
    Partition = 'CN=Configuration,DC=jaapbrasser,DC=com'
    Properties = 'tombstoneLifetime'
}
Get-ADObject @HashSplat | Select-Object -Property tombstoneLifetime

Update to Get-RemoteProgram – Get list of installed programs on remote or local computer

Over the weekend I have taken a look at the request and current functionality of my Get-RemoteProgram script. A script that gathers the installed programs installed on the local or remote systems by querying the registry and displaying the results to the console as PowerShell objects.

Get-RemoteProgram – Get list of installed programs on remote or local computer

Three new improvements have been implemented to the script:

  • Correctly searches the Wow6432Node for 32 bit applications on 64 bit systems
  • Added a new parameter -Property to specify additional properties to be loaded from the registry
  • Added support for the pipeline to be used to supply the function with computer names

The new parameter -Property is the biggest change to this script, this for example allows direct un-installation based on the output of Get-RemoteProgram, for example:

Get-RemoteProgram -Property UninstallString |
Where-Object {$_.ProgramName -match 'java'} | ForEach-Object {
    cmd /c $_.uninstallstring
}

Here are some additional examples of how the script can be used:

.EXAMPLE
Get-RemoteProgram

Description:
Will generate a list of installed programs on local machine

.EXAMPLE
Get-RemoteProgram -ComputerName server01,server02

Description:
Will generate a list of installed programs on server01 and server02

.EXAMPLE
Get-RemoteProgram -ComputerName Server01 -Property DisplayVersion,VersionMajor

Description:
Will gather the list of programs from Server01 and attempts to retrieve the displayversion and versionmajor subkeys from the registry for each installed program

.EXAMPLE
'server01','server02' | Get-RemoteProgram -Property Uninstallstring

Description
Will retrieve the installed programs on server01/02 that are passed on to the function through the pipeline and also retrieves the uninstall string for each program

Active Directory Friday: Search for computers accounts

I have decided to reintroduce Active Directory Friday on my blog, so today is the start of the new series of articles on Friday. The format remains the same as the previous posts. Usually the examples will be written by using .Net objects or the [adsi] and [adsisearcher] accelerators, although occasionally examples using the Active Directory cmdlets will be posted. My preference for avoiding the cmdlets is mostly compatibility, usually there is only a select number of systems that has access to the Active Directory module, so it pays off to know the native method as well.

Today we will take a look at how to find computer objects in Active Directory using the DirectoryServices.DirectorySearcher object. In order to search for computer objects the following properties of this object will be set:

  • Filter – This contains the LDAP filter used to select only the computer objects by specifying the objectcategory
  • PageSize – This allows for paging to occur, by specifying the pagesize more than 1000 results can be returned
$Searcher = New-Object DirectoryServices.DirectorySearcher -Property @{
    Filter = '(objectCategory=computer)'
    PageSize = 500
}
$Searcher.FindAll()

To search in a specific organizational unit the SearchRoot property can be used, only computer objects in the Servers OU will be returned by this search:

$Searcher = New-Object DirectoryServices.DirectorySearcher -Property @{
    Filter = '(objectCategory=computer)'
    PageSize = 500
    SearchRoot = 'LDAP://OU=Servers,DC=jaapbrasser,DC=com'
    SearchScope = 'Subtree'
}
$Searcher.FindAll()

The SearchScope property has been set to Subtree, which means that the OU will be recursively searched through and all child-ous will be included in the search. There are a total of three options available for the SearchRoot property:

  • Base – Only returns a single objects
  • OneLevel – Only searches the current container, will not recursively search
  • Subtree – Searches recursively through all child containers