Skip to content

Instantly share code, notes, and snippets.

@aaronparker
Last active October 2, 2021 11:42
Show Gist options
  • Save aaronparker/74fae5b7887b4e46040a6adc194ab383 to your computer and use it in GitHub Desktop.
Save aaronparker/74fae5b7887b4e46040a6adc194ab383 to your computer and use it in GitHub Desktop.
Collect Windows user folder status and OneDrive Known Folder move and post to Azure Monitor
<#
.SYNOPSIS
Get user folder sizes to determine impact on OneDrive Known Folder Move
#>
[CmdletBinding()]
Param (
[Parameter(Mandatory = $False)]
# Update with Log Analytics Workspace ID
[System.String] $CustomerId = "",
[Parameter(Mandatory = $False)]
# Update with Log Analytics Primary or Secondary key
[System.String] $SharedKey = "",
[Parameter(Mandatory = $False)]
[System.String] $CustomLog = "UserFolders"
)
# Record script start time
$StartTime = [System.DateTime]::Now
# You can use an optional field to specify the timestamp from the data.
# If the time field is not specified, Azure Monitor assumes the time is the message ingestion time
$TimeStampField = ""
#region Functions
# Get directory size
Function Get-DirectorySize ($Path) {
If (Test-Path -Path $Path -PathType "Container") {
$params = @{
Path = $Path
Recurse = $True
ErrorAction = "SilentlyContinue"
}
$PathSize = Get-ChildItem @params | Measure-Object -Property "Length" -Sum -ErrorAction "SilentlyContinue"
$Size = [System.Int64] $PathSize.Sum
If ($Size -gt 0) {
If ($ExecutionContext.SessionState.LanguageMode -eq "ConstrainedLanguage") {
# Convert to MB
Write-Output -InputObject ($Size / 1MB)
}
Else {
# Convert to MB and return 2 decimal places
Write-Output -InputObject ([System.Math]::Round(($Size) / 1MB, 2))
}
}
Else {
Write-Output -InputObject 0
}
}
Else {
Write-Output -InputObject 0
}
}
# Function to create the authorization signature
Function New-Signature ($CustomerId, $SharedKey, $Date, $ContentLength, $Method, $ContentType, $Resource) {
$xHeaders = "x-ms-date:" + $Date
$stringToHash = $Method + "`n" + $ContentLength + "`n" + $ContentType + "`n" + $xHeaders + "`n" + $Resource
$bytesToHash = [Text.Encoding]::UTF8.GetBytes($stringToHash)
$keyBytes = [System.Convert]::FromBase64String($sharedKey)
$sha256 = New-Object -TypeName "System.Security.Cryptography.HMACSHA256"
$sha256.Key = $keyBytes
$calculatedHash = $sha256.ComputeHash($bytesToHash)
$encodedHash = [System.Convert]::ToBase64String($calculatedHash)
$authorization = "SharedKey {0}:{1}" -f $customerId, $encodedHash
Return $authorization
}
# Function to create and post the request
Function Send-LogAnalyticsData ($CustomerId, $SharedKey, $Body, $LogType) {
# Validate that payload data does not exceed limits
if ($Body.Length -gt (31.9 * 1024 * 1024)) {
Throw "Upload payload too large. Reduce payload size to below the 32Mb limit. Current payload size is: " + ($body.Length / 1024 / 1024).ToString("#.#") + "Mb"
}
# Enable TLS 1.2 support
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
$Method = "POST"
$ContentType = "application/json"
$Resource = "/api/logs"
$Rfc1123date = [System.DateTime]::UtcNow.ToString("r")
$ContentLength = $Body.Length
$params = @{
CustomerId = $CustomerId
SharedKey = $SharedKey
Date = $Rfc1123date
ContentLength = $ContentLength
Method = $Method
ContentType = $ContentType
Resource = $Resource
}
$signature = New-Signature @params
try {
$Headers = @{
"Authorization" = $signature;
"Log-Type" = $logType;
"x-ms-date" = $rfc1123date;
"time-generated-field" = $TimeStampField;
}
$params = @{
Uri = "https://" + $customerId + ".ods.opinsights.azure.com" + $resource + "?api-version=2016-04-01"
Method = $Method
ContentType = $ContentType
Headers = $Headers
Body = $Body
UseBasicParsing = $True
}
$response = Invoke-WebRequest @params
$PayloadSize = ("Upload payload size is " + ($Body.Length / 1024).ToString("#.#") + "Kb ")
$StatusMessage = "$($response.StatusCode) : $($PayloadSize)"
}
catch {
Throw $_.Exception.Message
}
Return $StatusMessage
}
#endregion
#region script
#Get Common data for App and Device Inventory:
#Get Intune DeviceID and ManagedDeviceName
If (@(Get-ChildItem HKLM:SOFTWARE\Microsoft\Enrollments\ -Recurse | Where-Object { $_.PSChildName -eq 'MS DM Server' })) {
$MSDMServerInfo = Get-ChildItem HKLM:SOFTWARE\Microsoft\Enrollments\ -Recurse | Where-Object { $_.PSChildName -eq 'MS DM Server' }
$ManagedDeviceInfo = Get-ItemProperty -LiteralPath "Registry::$($MSDMServerInfo)"
}
$ManagedDeviceName = $ManagedDeviceInfo.EntDeviceName
$ManagedDeviceID = $ManagedDeviceInfo.EntDMID
# Let's first determine what OneDrive says about KFM
try {
$params = @{
Path = "Registry::HKEY_CURRENT_USER\SOFTWARE\Microsoft\OneDrive\Accounts\Business1\"
Name = "KfmFoldersProtectedNow"
ErrorAction = "SilentlyContinue"
}
$KfmFoldersProtectedNow = Get-ItemPropertyValue @params
}
catch {
$KfmFoldersProtectedNow = 0
}
If ($KfmFoldersProtectedNow -eq 3584) {
$KfmEnabled = $True
}
Else {
$KfmEnabled = $False
}
# Get the OneDrive signed in username
try {
$params = @{
Path = "Registry::HKEY_CURRENT_USER\SOFTWARE\Microsoft\OneDrive\Accounts\Business1\"
Name = "UserEmail"
ErrorAction = "SilentlyContinue"
}
$OneDriveUserName = Get-ItemPropertyValue @params
}
catch {
$OneDriveUserName = "NotSignedIn"
}
# Get the OneDrive sync folder
try {
$params = @{
Path = "Registry::HKEY_CURRENT_USER\SOFTWARE\Microsoft\OneDrive\Accounts\Business1\"
Name = "UserFolder"
ErrorAction = "SilentlyContinue"
}
$OneDriveUserFolderPath = Get-ItemPropertyValue @params
}
catch {
$OneDriveUserFolderPath = "NoSyncFolder"
}
# Get paths to user folders; Assume default user folder locations; English OS
$UserProfilePath = [System.Environment]::GetFolderPath("UserProfile")
$DesktopPath = [System.IO.Path]::Combine($UserProfilePath, "Desktop")
$DocumentsPath = [System.IO.Path]::Combine($UserProfilePath, "Documents")
$PicturesPath = [System.IO.Path]::Combine($UserProfilePath, "Pictures")
# Get the size of the Desktop folder
$TotalDesktopMb = Get-DirectorySize -Path $DesktopPath
# Get the size of the Documents folder
$TotalDocumentsMb = Get-DirectorySize -Path $DocumentsPath
# Get the size of the Pictures folder
$TotalPicturesMb = Get-DirectorySize -Path $PicturesPath
# Measure time taken
$EndTime = [System.DateTime]::Now
$TimeTaken = $($EndTime - $StartTime).Seconds
# Create the object
$Properties = [Ordered] @{
"ComputerName" = $Env:ComputerName
"ManagedDeviceName" = $ManagedDeviceName
"ManagedDeviceID" = $ManagedDeviceID
"UserEmail" = $OneDriveUserName
"OneDriveSyncPath" = $OneDriveUserFolderPath
"DesktopSizeMb" = $TotalDesktopMb
"DocumentsSizeMb" = $TotalDocumentsMb
"PicturesSizeMb" = $TotalPicturesMb
"KfmEnabled" = $KfmEnabled
"KfmFoldersProtectedNow" = $KfmFoldersProtectedNow
"GatherElapsedSec" = $TimeTaken
}
$UserFolders = New-Object -TypeName "PSObject" -Property $Properties
# Submit the data to the API endpoint
$UserFoldersJson = $UserFolders | ConvertTo-Json
$params = @{
CustomerId = $customerId
SharedKey = $sharedKey
Body = ([System.Text.Encoding]::UTF8.GetBytes($UserFoldersJson))
LogType = $CustomLog
}
$LogResponse = Send-LogAnalyticsData @params
#endregion
#Report back status
$OutputMessage = "InventoryDate:$(Get-Date -Format "dd-MM HH:mm") "
If ($LogResponse -match "200 :") {
$OutputMessage = $OutPutMessage + " UserFolders:OK " + $LogResponse
Write-Output $OutputMessage
Exit 0
}
Else {
$OutputMessage = $OutPutMessage + " UserFolders:Fail "
Write-Output $OutputMessage
Exit 1
}
#endregion script
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment