List mounted PST files with PowerShell
Need to get a list of PST files in use in your enterprise? Look no further!
This script should be run with the logged on user’s privileges i.e. not elevated. It must be run on each PC individually e.g. with an SCCM package.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
#Get the current date and time, computer name, user name and path to share where to save the list of PST files found $date_time = Get-Date -Format yyyy-MM-dd_HH-mm-ss $computername = $env:COMPUTERNAME $sharepath = "\\server\share" $username = $env:USERNAME #Test if Outlook is running. Script should only run when Outlook is running. Otherwise a pop-up appears on the user's screen... try { $proc = Get-Process -Name OUTLOOK -ErrorAction Stop #Get the version of Office $prodver = $proc.ProductVersion } catch { "$date_time;$computername;Outlook is not running;N/A;N/A;$username" | Out-File -FilePath ("$sharepath\$computername" + "_PST_files.csv") -Append break } #Load Outlook object from current user's profile $Outlook = New-Object -ComObject 'Outlook.Application' -ErrorAction 'Stop' #Get all Outlook stores of type 3 (PST) $pstobjects = $outlook.GetNameSpace('MAPI').Stores | Where-Object {$_.ExchangeStoreType -eq 3} if ($pstobjects -eq $null) { "$date_time;$computername;No PST files found;N/A;$prodver;$username" | Out-File -FilePath ("$sharepath\$computername" + "_PST_files.csv") -Append break } #For each PST file found... foreach ($pstobject in $pstobjects) { #get the PST file path $filepath = $pstobject.filepath #Remove invalid characters from from file path if ($filepath -match ":") { $drive = (Split-Path $filepath -Qualifier).Replace(':','') $leaf = Split-Path $filepath -NoQualifier $unc = Join-Path (Get-PSDrive $drive)[0].DisplayRoot -ChildPath $leaf $filepathcleaned = $unc } else { $filepathcleaned = $pstobject.filepath -replace [regex]::escape('?\UNC\'),'' } #If the file exists, get the size and output data to a CSV file. The name includes the computer name. if (test-path $filepathcleaned) { $filesize = (Get-Item $filepathcleaned).length "$date_time;$computername;$filepathcleaned;$filesize;$prodver;$username" | Out-File -FilePath ("$sharepath\$computername" + "_PST_files.csv") -Append } } |
In order to make the script execution transparent for the end user, I used a PowerShell App Deploy Tool package which was then deployed by SCCM. To make sure the script was accessible for the regular user account, I used the PS App Deploy Toolkit cmdlet “Copy-File” like this:
1 2 3 4 5 6 7 8 9 10 |
$temppath = 'c:\temp' if (!(Test-Path $temppath)) { try { New-Item $temppath -type directory -ErrorAction Stop | Out-Null } catch { break } } Copy-File -Path "$dirSupportFiles\DetectPSTfiles.ps1" -Destination "$temppath\DetectPSTfiles.ps1" |
To execute the script as the logged on user, I used the PowerShell App Deploy Tool cmdlet “Execute-ProcessAsUser”, which creates and triggers a scheduled task:
1 |
Execute-ProcessAsUser -Path "$PSHOME\powershell.exe" -Parameters "-Command & { & `"$temppath\DetectPSTfiles.ps1`"; Exit `$LastExitCode }" -RunLevel LeastPrivilege |
The script will create a single CSV file for each PC you deploy to. To make this into one big CSV file, I used the following script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
#Get the date and time and define the input/output paths $date_time = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' $files = Get-ChildItem -Path "\\server\share" -Depth 0 -Filter "*.csv" $outfilepath = ("c:\temp\" + $date_time + "_pstoverview.csv") #Create headers in CSV file "Timestamp;Computer;Path;Size;Outlook version;User ID;User name;User description;User location;User department;User email;User company;User title;Manager ID;Manager email" | Out-File -FilePath $outfilepath -Append #Import each CSV file into big CSV file foreach ($file in $files) { $file | Get-Content | Out-File -FilePath $outfilepath -Append } #Import big CSV file in order to get userinfo from AD $csv = Import-Csv $outfilepath -Delimiter ';' $numberoflines = $csv.Count $lastuserID = $null $i = 1 #For each line in the big CSV, get the user name and query AD for additional info foreach ($line in $csv) { $userID = $line.'User ID' write-host "Processing line $i of $numberoflines - User: $userID" $i++ #Skip repeat user names if (($userID -ne $lastuserID) -and ($userID -ne $null)) { write-host "New user: $userID ... querying AD" #Resetting variables to avoid duplicates in case the queries fail $username = $null $userdepartment = $null $userdescription = $null $userlocation = $null $usermanagerSAMID = $null $usermanagerEMAIL = $null $useremail = $null $usercompany = $null $usertitle = $null #Query AD and save variables $username = ((dsquery user -samid $userID | dsget user -display)[1]).Trim() $userdepartment = ((dsquery user -samid $userID | dsget user -dept)[1]).Trim() $userdescription = ((dsquery user -samid $userID | dsget user -desc)[1]).Trim() $userlocation = ((dsquery user -samid $userID | dsget user -office)[1]).Trim() $usermanager = (dsquery user -samid $userID | dsget user -mgr)[1].Trim() if ($usermanager -ne "") { $usermanagerSAMID = (($usermanager | dsget user -samid)[1]).Trim() $usermanagerEMAIL = (($usermanager | dsget user -email)[1]).Trim() } $useremail = ((dsquery user -samid $userID | dsget user -email)[1]).Trim() $usercompany = ((dsquery user -samid $userID | dsget user -company)[1]).Trim() $usertitle = ((dsquery user -samid $userID | dsget user -title)[1]).Trim() } elseif (($userID -eq $lastuserID) -and ($userID -ne $null)) { write-host "Same user...skipped query" } else { write-host "No user found...skipped query" } $line.'User name' = $username $line.'User department' = $userdepartment $line.'User description' = $userdescription $line.'User location' = $userlocation $line.'Manager ID' = $usermanagerSAMID $line.'Manager email' = $usermanagerEMAIL $line.'User email' = $useremail $line.'User company' = $usercompany $line.'User title' = $usertitle $lastuserID = $userID } #Export CSV object to file $csv | Export-Csv c:\temp\out.csv -Delimiter ';' |
2 Comments
Join the discussion and tell us your opinion.
Exactly what I need! Thanks for sharing!
Thanks…glad you could use it 🙂
Actually I just tweaked it a bit. Apparently some users put commas “,” in their PST file names!!! So i changed the formatting of the output files to semicolon separated instead of of comma separated.